private void doTest(String source, String expected) { PsiJavaFile file = (PsiJavaFile)createLightFile("test.java", source); FileASTNode fileNode = file.getNode(); assertNotNull(fileNode); assertFalse(fileNode.isParsed()); StubElement lightTree = myBuilder.buildStubTree(file); assertFalse(fileNode.isParsed()); file.getNode().getChildren(null); // force switch to AST StubElement astBasedTree = myBuilder.buildStubTree(file); assertTrue(fileNode.isParsed()); assertEquals("light tree differs", expected, DebugUtil.stubTreeToString(lightTree)); assertEquals("AST-based tree differs", expected, DebugUtil.stubTreeToString(astBasedTree)); }
public void testEqualPointerRangesWhenCreatedFromStubAndAST() { final PsiFile file = configureByText(JavaFileType.INSTANCE, "class S {\n" + "}"); PsiClass aClass = ((PsiJavaFile)file).getClasses()[0]; assertNotNull(((PsiFileImpl)file).getStubTree()); final SmartPointerManager manager = getPointerManager(); final SmartPsiElementPointer<PsiClass> pointer1 = createPointer(aClass); Segment range1 = pointer1.getRange(); manager.removePointer(pointer1); final FileASTNode node = file.getNode(); final SmartPsiElementPointer<PsiClass> pointer2 = createPointer(aClass); assertEquals(range1, pointer2.getRange()); assertNotNull(node); }
public void testEqualPointersWhenCreatedFromStubAndAST() { PsiJavaFile file = (PsiJavaFile)myJavaFacade.findClass("AClass", GlobalSearchScope.allScope(getProject())).getContainingFile(); int hash1 = file.getClasses()[0].hashCode(); final SmartPsiElementPointer<PsiClass> pointer1 = createPointer(file.getClasses()[0]); assertNotNull(((PsiFileImpl)file).getStubTree()); PlatformTestUtil.tryGcSoftlyReachableObjects(); final FileASTNode node = file.getNode(); final SmartPsiElementPointer<PsiClass> pointer2 = createPointer(file.getClasses()[0]); assertFalse(hash1 == file.getClasses()[0].hashCode()); assertEquals(pointer1, pointer2); assertEquals(pointer1.getRange(), pointer2.getRange()); assertNotNull(node); }
public static Object findInvalidationTrace(@Nullable ASTNode element) { while (element != null) { Object trace = element.getUserData(INVALIDATION_TRACE); if (trace != null) { return trace; } ASTNode parent = element.getTreeParent(); if (parent == null && element instanceof FileASTNode) { PsiElement psi = element.getPsi(); trace = psi == null ? null : psi.getUserData(INVALIDATION_TRACE); if (trace != null) { return trace; } } element = parent; } return null; }
public static void cacheSingleFile(Project project, VirtualFile openFile) { if(openFile.exists()) { //cache attributes PsiManager psiManager = PsiManager.getInstance(project); if(psiManager == null) return; PsiFile psiFile = psiManager.findFile(openFile); if(psiFile == null) return; FileASTNode astNode = psiFile.getNode(); if(astNode == null) return; HashSet<String> rs = findAllVariables(astNode.getChildren(null), PerlTypes.VARIABLE, false); if(rs == null) return; for (String str : rs) { addCachedVariables(null, str); } //cache subs ArrayList<Package> packages = ModulesContainer.getPackageListFromFile(openFile.getPath()); for (int i = 0; i < packages.size(); i++) { ArrayList<Sub> subs = packages.get(i).getAllSubs(); for (int j = 0; j < subs.size(); j++) { addCachedSub(null, subs.get(j)); } } } }
protected void addLineFeedAfter(GrImportStatement result) { final GroovyCodeStyleSettings settings = CodeStyleSettingsManager.getInstance(getProject()).getCurrentSettings().getCustomSettings(GroovyCodeStyleSettings.class); final PackageEntryTable layoutTable = settings.IMPORT_LAYOUT_TABLE; final PackageEntry[] entries = layoutTable.getEntries(); PsiElement next = result.getNextSibling(); if (isWhiteSpace(next)) next = next.getNextSibling(); if (hasElementType(next, GroovyTokenTypes.mSEMI)) next = next.getNextSibling(); while (isWhiteSpace(next)) { next = next.getNextSibling(); } if (next instanceof GrImportStatement) { final int idx_after = getPackageEntryIdx(entries, (GrImportStatement)next); final int idx = getPackageEntryIdx(entries, result); final int spaceCount = getMaxSpaceCount(entries, idx, idx_after); final FileASTNode node = getNode(); while (isWhiteSpace(next.getPrevSibling())) { node.removeChild(next.getPrevSibling().getNode()); } node.addLeaf(GroovyTokenTypes.mNLS, StringUtil.repeat("\n", spaceCount + 1), next.getNode()); } }
private void doQueue(@Nonnull Project project, @Nonnull Document document, @Nonnull List<Pair<PsiFileImpl, FileASTNode>> oldFileNodes, @Nonnull Object reason, @Nullable TransactionId context, @Nonnull CharSequence lastCommittedText) { synchronized (lock) { if (!project.isInitialized()) return; // check the project is disposed under lock. CommitTask newTask = createNewTaskAndCancelSimilar(project, document, oldFileNodes, reason, context, lastCommittedText, false); documentsToCommit.offer(newTask); log(project, "Queued", newTask, reason); wakeUpQueue(); } }
@Nonnull private CommitTask createNewTaskAndCancelSimilar(@Nonnull Project project, @Nonnull Document document, @Nonnull List<Pair<PsiFileImpl, FileASTNode>> oldFileNodes, @Nonnull Object reason, @Nullable TransactionId context, @Nonnull CharSequence lastCommittedText, boolean canReQueue) { synchronized (lock) { for (Pair<PsiFileImpl, FileASTNode> pair : oldFileNodes) { assert pair.first.getProject() == project; } CommitTask newTask = new CommitTask(project, document, oldFileNodes, createProgressIndicator(), reason, context, lastCommittedText); cancelAndRemoveFromDocsToCommit(newTask, reason, canReQueue); cancelAndRemoveCurrentTask(newTask, reason, canReQueue); cancelAndRemoveFromDocsToApplyInEDT(newTask, reason, canReQueue); return newTask; } }
CommitTask(@Nonnull final Project project, @Nonnull final Document document, @Nonnull final List<Pair<PsiFileImpl, FileASTNode>> oldFileNodes, @Nonnull ProgressIndicator indicator, @Nonnull Object reason, @Nullable TransactionId context, @Nonnull CharSequence lastCommittedText) { this.document = document; this.project = project; this.indicator = indicator; this.reason = reason; myCreationContext = context; myLastCommittedText = lastCommittedText; myOldFileNodes = oldFileNodes; modificationSequence = ((DocumentEx)document).getModificationSequence(); }
@Nonnull public static Trinity<DiffLog, ASTNode, ASTNode> reparse(@Nonnull final PsiFile file, @Nonnull FileASTNode oldFileNode, @Nonnull TextRange changedPsiRange, @Nonnull final CharSequence newFileText, @Nonnull final ProgressIndicator indicator, @Nonnull CharSequence lastCommittedText) { PsiFileImpl fileImpl = (PsiFileImpl)file; final Couple<ASTNode> reparseableRoots = findReparseableRoots(fileImpl, oldFileNode, changedPsiRange, newFileText); DiffLog diffLog; ASTNode oldRoot; ASTNode newRoot; if (reparseableRoots == null) { Pair.NonNull<DiffLog, FileElement> pair = makeFullParse(fileImpl, oldFileNode, newFileText, indicator, lastCommittedText); oldRoot = oldFileNode; newRoot = pair.getSecond(); diffLog = pair.getFirst(); } else { oldRoot = reparseableRoots.first; newRoot = reparseableRoots.second; diffLog = mergeTrees(fileImpl, oldRoot, newRoot, indicator, lastCommittedText); } return Trinity.create(diffLog, oldRoot, newRoot); }
@NotNull public static <T extends PsiJavaCodeReferenceElement> JavaResolveResult[] multiResolveImpl( @NotNull T element, boolean incompleteCode, @NotNull ResolveCache.PolyVariantContextResolver<? super T> resolver) { FileASTNode fileElement = SharedImplUtil.findFileElement(element.getNode()); if (fileElement == null) { PsiUtilCore.ensureValid(element); LOG.error("fileElement == null!"); return JavaResolveResult.EMPTY_ARRAY; } PsiFile psiFile = SharedImplUtil.getContainingFile(fileElement); PsiManager manager = psiFile == null ? null : psiFile.getManager(); if (manager == null) { PsiUtilCore.ensureValid(element); LOG.error("getManager() == null!"); return JavaResolveResult.EMPTY_ARRAY; } boolean valid = psiFile.isValid(); if (!valid) { PsiUtilCore.ensureValid(element); LOG.error("psiFile.isValid() == false!"); return JavaResolveResult.EMPTY_ARRAY; } if (element instanceof PsiMethodReferenceExpression) { // method refs: do not cache results during parent conflict resolving, acceptable checks, etc final Map<PsiElement, PsiType> map = LambdaUtil.ourFunctionTypes.get(); if (map != null && map.containsKey(element)) { return (JavaResolveResult[])resolver.resolve(element, psiFile, incompleteCode); } } return multiResolveImpl(manager.getProject(), psiFile, element, incompleteCode, resolver); }
public static FileASTNode findFileElement(@NotNull ASTNode element) { if (CHECK_FOR_READ_ACTION && element instanceof ElementBase) { ApplicationManager.getApplication().assertReadAccessAllowed(); } ASTNode parent = element.getTreeParent(); while (parent != null) { element = parent; parent = parent.getTreeParent(); } if (element instanceof FileASTNode) { return (FileASTNode)element; } return null; }
public static void processRanges(@Nullable PsiElement element, CharSequence text, int cursorOffset, Editor editor, Processor<TextRange> consumer) { if (element == null) return; PsiFile file = element.getContainingFile(); FileViewProvider viewProvider = file.getViewProvider(); processInFile(element, consumer, text, cursorOffset, editor); for (PsiFile psiFile : viewProvider.getAllFiles()) { if (psiFile == file) continue; FileASTNode fileNode = psiFile.getNode(); if (fileNode == null) continue; ASTNode nodeAt = fileNode.findLeafElementAt(element.getTextOffset()); if (nodeAt == null) continue; PsiElement elementAt = nodeAt.getPsi(); while (!(elementAt instanceof PsiFile) && elementAt != null) { if (elementAt.getTextRange().contains(element.getTextRange())) break; elementAt = elementAt.getParent(); } if (elementAt == null) continue; processInFile(elementAt, consumer, text, cursorOffset, editor); } }
/** * Returns closest previous node of given class, as input file would have it. * * @param elt node from which to look for a previous statement. * @param elementTypes selected element types. * @return previous statement, or null. */ @Nullable private static PsiElement getPrevNodeOf(PsiElement elt, TokenSet elementTypes) { ASTNode seeker = elt.getNode(); while (seeker != null) { ASTNode feeler = seeker.getTreePrev(); if (feeler != null && (feeler.getElementType() == PyElementTypes.FUNCTION_DECLARATION || feeler.getElementType() == PyElementTypes.CLASS_DECLARATION) && elementTypes.contains(feeler.getElementType())) { return feeler.getPsi(); } if (feeler != null) { seeker = TreeUtil.getLastChild(feeler); } else { // we were the first subnode // find something above the parent node we've not exhausted yet seeker = seeker.getTreeParent(); if (seeker instanceof FileASTNode) return null; // all file nodes have been looked up, in vain } if (seeker != null && elementTypes.contains(seeker.getElementType())) { return seeker.getPsi(); } } // here elt is null or a PsiFile is not up in the parent chain. return null; }
/** Currently only folding top-level nodes. */ @Override public FoldingDescriptor[] buildFoldRegions(ASTNode node, Document document) { List<FoldingDescriptor> descriptors = Lists.newArrayList(); if (node instanceof FileASTNode) { for (ASTNode child : node.getChildren(null)) { addDescriptors(descriptors, child); } } else if (isTopLevel(node)) { addDescriptors(descriptors, node); } return descriptors.toArray(new FoldingDescriptor[0]); }
private void nodeToString(ASTNode node, StringBuilder builder) { if (node instanceof LeafElement || node.getPsi() == null) { return; } PsiElement[] childPsis = getChildBuildPsis(node); if (node instanceof FileASTNode) { appendChildren(childPsis, builder, false); return; } builder.append(node.getElementType()); appendChildren(childPsis, builder, true); }
@Override public void invoke(@NotNull final Project project, Editor editor, final PsiFile file) throws IncorrectOperationException { PsiWhiteSpace newline = HaskellElementFactory.createNewLine(project); HaskellPpragma ppragma = HaskellElementFactory.createPpragmaFromText( project, "{-# ANN module (\"HLint: ignore " + hint + "\"::String) #-}"); FileASTNode fileNode = file.getNode(); ASTNode[] nodes; ASTNode node; // If the user has imports, place the pragma after them. node = fileNode.findChildByType(HaskellTypes.BODY); if (node != null) { nodes = node.getChildren(TokenSet.create(HaskellTypes.IMPDECL)); if (nodes.length > 0) { PsiElement element = node.getPsi(); element.addBefore(newline, element.addAfter(ppragma, nodes[nodes.length - 1].getPsi())); return; } } // If the user has a module declaration, place the pragma after it. node = fileNode.findChildByType(HaskellTypes.MODULEDECL); if (node != null) { file.addBefore(newline, file.addAfter(ppragma, node.getPsi())); return; } // If the user has any existing pragmas, place the pragma after them. nodes = fileNode.getChildren(TokenSet.create(HaskellTypes.PPRAGMA)); if (nodes.length > 0) { file.addBefore(newline, file.addAfter(ppragma, nodes[nodes.length - 1].getPsi())); return; } // Otherwise, just insert the pragma at the top of the file. file.addAfter(newline, file.addBefore(ppragma, file.getFirstChild())); }
static void assertCommitSuccessful(Editor editor, PsiFile psiFile) { Document document = editor.getDocument(); int docLength = document.getTextLength(); int psiLength = psiFile.getTextLength(); PsiDocumentManager manager = PsiDocumentManager.getInstance(psiFile.getProject()); boolean committed = !manager.isUncommited(document); if (docLength == psiLength && committed) { return; } String message = "unsuccessful commit:"; message += "\nmatching=" + (psiFile == manager.getPsiFile(document)); message += "\ninjectedEditor=" + (editor instanceof EditorWindow); message += "\ninjectedFile=" + InjectedLanguageManager.getInstance(psiFile.getProject()).isInjectedFragment(psiFile); message += "\ncommitted=" + committed; message += "\nfile=" + psiFile.getName(); message += "\nfile class=" + psiFile.getClass(); message += "\nfile.valid=" + psiFile.isValid(); message += "\nlanguage=" + psiFile.getLanguage(); message += "\ndoc.length=" + docLength; message += "\npsiFile.length=" + psiLength; String fileText = psiFile.getText(); if (fileText != null) { message += "\npsiFile.text.length=" + fileText.length(); } FileASTNode node = psiFile.getNode(); if (node != null) { message += "\nnode.length=" + node.getTextLength(); String nodeText = node.getText(); if (nodeText != null) { message += "\nnode.text.length=" + nodeText.length(); } } message += "\n" + DebugUtil.currentStackTrace(); throw new LogEventException("Commit unsuccessful", message, new Attachment(psiFile.getViewProvider().getVirtualFile().getPath() + "_file.txt", fileText), createAstAttachment(psiFile, psiFile), new Attachment("docText.txt", document.getText())); }
protected void addLineFeedBefore(GrImportStatement result) { final GroovyCodeStyleSettings settings = CodeStyleSettingsManager.getInstance(getProject()).getCurrentSettings().getCustomSettings(GroovyCodeStyleSettings.class); final PackageEntryTable layoutTable = settings.IMPORT_LAYOUT_TABLE; final PackageEntry[] entries = layoutTable.getEntries(); PsiElement prev = result.getPrevSibling(); while (isWhiteSpace(prev)) { prev = prev.getPrevSibling(); } if (hasElementType(prev, GroovyTokenTypes.mSEMI)) prev = prev.getPrevSibling(); if (isWhiteSpace(prev)) prev = prev.getPrevSibling(); if (prev instanceof GrImportStatement) { final int idx_before = getPackageEntryIdx(entries, (GrImportStatement)prev); final int idx = getPackageEntryIdx(entries, result); final int spaceCount = getMaxSpaceCount(entries, idx_before, idx); //skip space and semicolon after import if (isWhiteSpace(prev.getNextSibling()) && hasElementType(prev.getNextSibling().getNextSibling(), GroovyTokenTypes.mSEMI)) prev = prev.getNextSibling().getNextSibling(); final FileASTNode node = getNode(); while (isWhiteSpace(prev.getNextSibling())) { node.removeChild(prev.getNextSibling().getNode()); } node.addLeaf(GroovyTokenTypes.mNLS, StringUtil.repeat("\n", spaceCount + 1), result.getNode()); } }
@Nonnull public abstract DiffLog reparseRange(@Nonnull PsiFile file, @Nonnull FileASTNode oldFileNode, @Nonnull TextRange changedPsiRange, @Nonnull CharSequence newText, @Nonnull ProgressIndicator progressIndicator, @Nonnull CharSequence lastCommittedText) throws IncorrectOperationException;
@Nonnull private static List<Pair<PsiFileImpl, FileASTNode>> getAllFileNodes(@Nonnull PsiFile file) { if (!file.isValid()) { throw new PsiInvalidElementAccessException(file, "File " + file + " is invalid, can't commit"); } if (file instanceof PsiCompiledFile) { throw new IllegalArgumentException("Can't commit ClsFile: " + file); } return ContainerUtil.map(file.getViewProvider().getAllFiles(), root -> Pair.create((PsiFileImpl)root, root.getNode())); }
public static FileASTNode findFileElement(@Nonnull ASTNode element) { ASTNode parent = element.getTreeParent(); while (parent != null) { element = parent; parent = parent.getTreeParent(); } if (element instanceof FileASTNode) { return (FileASTNode)element; } return null; }
@Override @Nonnull public DiffLog reparseRange(@Nonnull final PsiFile file, @Nonnull FileASTNode oldFileNode, @Nonnull TextRange changedPsiRange, @Nonnull final CharSequence newFileText, @Nonnull final ProgressIndicator indicator, @Nonnull CharSequence lastCommittedText) { final PsiFileImpl fileImpl = (PsiFileImpl)file; final Couple<ASTNode> reparseableRoots = findReparseableRoots(fileImpl, oldFileNode, changedPsiRange, newFileText); return reparseableRoots != null ? mergeTrees(fileImpl, reparseableRoots.first, reparseableRoots.second, indicator, lastCommittedText) : makeFullParse(fileImpl, oldFileNode, newFileText, indicator, lastCommittedText).getFirst(); }
public @Nonnull LighterAST getLighterASTForPsiDependentIndex() { LighterAST lighterAST = getUserData(IndexingDataKeys.LIGHTER_AST_NODE_KEY); if (lighterAST == null) { FileASTNode node = getPsiFileForPsiDependentIndex().getNode(); lighterAST = myLighterASTShouldBeThreadSafe ? new TreeBackedLighterAST(node) : node.getLighterAST(); putUserData(IndexingDataKeys.LIGHTER_AST_NODE_KEY, lighterAST); } return lighterAST; }
@NotNull public static <T extends PsiJavaCodeReferenceElement> JavaResolveResult[] multiResolveImpl(@NotNull T element, boolean incompleteCode, @NotNull ResolveCache.PolyVariantContextResolver<? super T> resolver) { FileASTNode fileElement = SharedImplUtil.findFileElement(element.getNode()); if(fileElement == null) { PsiUtilCore.ensureValid(element); LOG.error("fileElement == null!"); return JavaResolveResult.EMPTY_ARRAY; } PsiFile psiFile = SharedImplUtil.getContainingFile(fileElement); PsiManager manager = psiFile == null ? null : psiFile.getManager(); if(manager == null) { PsiUtilCore.ensureValid(element); LOG.error("getManager() == null!"); return JavaResolveResult.EMPTY_ARRAY; } boolean valid = psiFile.isValid(); if(!valid) { PsiUtilCore.ensureValid(element); LOG.error("psiFile.isValid() == false!"); return JavaResolveResult.EMPTY_ARRAY; } if(element instanceof PsiMethodReferenceExpression) { // method refs: do not cache results during parent conflict resolving, acceptable checks, etc final Map<PsiElement, PsiType> map = LambdaUtil.ourFunctionTypes.get(); if(map != null && map.containsKey(element)) { return (JavaResolveResult[]) resolver.resolve(element, psiFile, incompleteCode); } } return multiResolveImpl(manager.getProject(), psiFile, element, incompleteCode, resolver); }
@Override public FileASTNode getNode() { return null; }
@Override FileASTNode getNode();
@Override public FileASTNode getNode() { throw createException(); }
public static PsiFile getContainingFile(ASTNode thisElement) { FileASTNode element = findFileElement(thisElement); PsiElement psiElement = element == null ? null : element.getPsi(); if (psiElement == null) return null; return psiElement.getContainingFile(); }
@Override public FileASTNode getNode() { return null; // TODO[max] throw new UnsupportedOperationException() }
static void assertCommitSuccessful(Editor editor, PsiFile psiFile) { Document document = editor.getDocument(); int docLength = document.getTextLength(); int psiLength = psiFile.getTextLength(); PsiDocumentManager manager = PsiDocumentManager.getInstance(psiFile.getProject()); boolean committed = !manager.isUncommited(document); if (docLength == psiLength && committed) { return; } FileViewProvider viewProvider = psiFile.getViewProvider(); String message = "unsuccessful commit:"; message += "\nmatching=" + (psiFile == manager.getPsiFile(document)); message += "\ninjectedEditor=" + (editor instanceof EditorWindow); message += "\ninjectedFile=" + InjectedLanguageManager.getInstance(psiFile.getProject()).isInjectedFragment(psiFile); message += "\ncommitted=" + committed; message += "\nfile=" + psiFile.getName(); message += "\nfile class=" + psiFile.getClass(); message += "\nfile.valid=" + psiFile.isValid(); message += "\nfile.physical=" + psiFile.isPhysical(); message += "\nfile.eventSystemEnabled=" + viewProvider.isEventSystemEnabled(); message += "\nlanguage=" + psiFile.getLanguage(); message += "\ndoc.length=" + docLength; message += "\npsiFile.length=" + psiLength; String fileText = psiFile.getText(); if (fileText != null) { message += "\npsiFile.text.length=" + fileText.length(); } FileASTNode node = psiFile.getNode(); if (node != null) { message += "\nnode.length=" + node.getTextLength(); String nodeText = node.getText(); if (nodeText != null) { message += "\nnode.text.length=" + nodeText.length(); } } VirtualFile virtualFile = viewProvider.getVirtualFile(); message += "\nvirtualFile=" + virtualFile; message += "\nvirtualFile.class=" + virtualFile.getClass(); message += "\n" + DebugUtil.currentStackTrace(); throw new LogEventException("Commit unsuccessful", message, new Attachment(virtualFile.getPath() + "_file.txt", fileText), createAstAttachment(psiFile, psiFile), new Attachment("docText.txt", document.getText())); }
@Override @Nullable public FileASTNode getNode() { return myWrappee.getNode(); }
private boolean isTopLevel(ASTNode node) { return node.getTreeParent() instanceof FileASTNode; }