/* * 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.lang.psi; import com.intellij.lang.*; import com.intellij.lang.impl.PsiBuilderImpl; import com.intellij.lang.java.JavaParserDefinition; import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.JavaTokenType; import com.intellij.psi.PsiFile; import com.intellij.psi.impl.DebugUtil; import com.intellij.psi.impl.java.stubs.JavaStubElementTypes; import com.intellij.psi.impl.source.DummyHolder; import com.intellij.psi.impl.source.tree.JavaElementType; import com.intellij.psi.impl.source.tree.SharedImplUtil; import com.intellij.psi.impl.source.tree.TreeElement; import com.intellij.psi.text.BlockSupport; import com.intellij.testFramework.LightIdeaTestCase; import junit.framework.AssertionFailedError; /** * @since Jan 21, 2005 * @author max */ public class PsiBuilderTest extends LightIdeaTestCase { private PsiBuilderImpl myBuilder; @Override protected void tearDown() throws Exception { myBuilder = null; super.tearDown(); } public void testEmptyProgram() throws Exception { myBuilder = createBuilder(""); final PsiBuilder.Marker fileMarker = myBuilder.mark(); fileMarker.done(JavaStubElementTypes.JAVA_FILE); ASTNode fileNode = myBuilder.getTreeBuilt(); assertNotNull(fileNode); assertEquals("", fileNode.getText()); } public void testProgramWithSingleKeyword() throws Exception { myBuilder = createBuilder("package"); final PsiBuilder.Marker fileMarker = myBuilder.mark(); assertEquals("package", myBuilder.getTokenText()); assertEquals(JavaTokenType.PACKAGE_KEYWORD, myBuilder.getTokenType()); final PsiBuilder.Marker packageStatementMarker = myBuilder.mark(); myBuilder.advanceLexer(); assertTrue(myBuilder.eof()); packageStatementMarker.done(JavaElementType.PACKAGE_STATEMENT); fileMarker.done(JavaStubElementTypes.JAVA_FILE); ASTNode fileNode = myBuilder.getTreeBuilt(); assertNotNull(fileNode); assertEquals("package", fileNode.getText()); assertSame(fileNode.getFirstChildNode(), fileNode.getLastChildNode()); ASTNode packageNode = fileNode.getFirstChildNode(); assertNotNull(packageNode); assertEquals("package", packageNode.getText()); assertEquals(JavaElementType.PACKAGE_STATEMENT, packageNode.getElementType()); ASTNode leaf = packageNode.getFirstChildNode(); assertNotNull(leaf); assertEquals(JavaTokenType.PACKAGE_KEYWORD, leaf.getElementType()); } private static PsiBuilderImpl createBuilder(final String text) { return createBuilder(text,null); } private static PsiBuilderImpl createBuilder(final String text, ASTNode originalTree) { final Language lang = StdFileTypes.JAVA.getLanguage(); final ParserDefinition parserDefinition = LanguageParserDefinitions.INSTANCE.forLanguage(lang); assertNotNull(parserDefinition); PsiFile psiFile = createFile("x.java", text); return new PsiBuilderImpl(getProject(), psiFile, parserDefinition, JavaParserDefinition.createLexer(LanguageLevel.JDK_1_5), SharedImplUtil.findCharTableByTree(psiFile.getNode()), text, originalTree, null); } public void testTrailingWhitespaces() throws Exception { myBuilder = createBuilder("foo\n\nx"); final PsiBuilder.Marker marker = myBuilder.mark(); while (!myBuilder.eof()) { myBuilder.advanceLexer(); } marker.done(JavaStubElementTypes.JAVA_FILE); assertEquals("foo\n\nx", myBuilder.getTreeBuilt().getText()); } public void testRollback() throws Exception { myBuilder = createBuilder("package"); PsiBuilder.Marker fileMarker = myBuilder.mark(); assertEquals("package", myBuilder.getTokenText()); assertEquals(JavaTokenType.PACKAGE_KEYWORD, myBuilder.getTokenType()); PsiBuilder.Marker packageStatementMarker = myBuilder.mark(); myBuilder.advanceLexer(); assertTrue(myBuilder.eof()); packageStatementMarker.done(JavaElementType.PACKAGE_STATEMENT); fileMarker.rollbackTo(); fileMarker = myBuilder.mark(); assertEquals("package", myBuilder.getTokenText()); assertEquals(JavaTokenType.PACKAGE_KEYWORD, myBuilder.getTokenType()); packageStatementMarker = myBuilder.mark(); myBuilder.advanceLexer(); assertTrue(myBuilder.eof()); packageStatementMarker.done(JavaElementType.PACKAGE_STATEMENT); fileMarker.done(JavaStubElementTypes.JAVA_FILE); ASTNode fileNode = myBuilder.getTreeBuilt(); assertNotNull(fileNode); assertEquals("package", fileNode.getText()); assertSame(fileNode.getFirstChildNode(), fileNode.getLastChildNode()); ASTNode packageNode = fileNode.getFirstChildNode(); assertNotNull(packageNode); assertEquals("package", packageNode.getText()); assertEquals(JavaElementType.PACKAGE_STATEMENT, packageNode.getElementType()); ASTNode leaf = packageNode.getFirstChildNode(); assertNotNull(leaf); assertEquals(JavaTokenType.PACKAGE_KEYWORD, leaf.getElementType()); } public void testDrop() throws Exception { myBuilder = createBuilder("package"); final PsiBuilder.Marker fileMarker = myBuilder.mark(); assertEquals("package", myBuilder.getTokenText()); assertEquals(JavaTokenType.PACKAGE_KEYWORD, myBuilder.getTokenType()); final PsiBuilder.Marker packageStatementMarker = myBuilder.mark(); myBuilder.advanceLexer(); assertTrue(myBuilder.eof()); packageStatementMarker.drop(); fileMarker.done(JavaStubElementTypes.JAVA_FILE); ASTNode fileNode = myBuilder.getTreeBuilt(); assertNotNull(fileNode); assertEquals("package", fileNode.getText()); assertSame(fileNode.getFirstChildNode(), fileNode.getLastChildNode()); ASTNode leaf = fileNode.getFirstChildNode(); assertNotNull(leaf); assertEquals(JavaTokenType.PACKAGE_KEYWORD, leaf.getElementType()); assertEquals("package", leaf.getText()); assertNull(leaf.getFirstChildNode()); } public void testAdvanceBeyondEof() { myBuilder = createBuilder("package"); for(int i=0; i<20; i++) { myBuilder.eof(); myBuilder.advanceLexer(); } assertTrue(myBuilder.eof()); } public void testAssertionFailureOnUnbalancedMarkers() { myBuilder = createBuilder("foo"); myBuilder.setDebugMode(true); PsiBuilder.Marker m = myBuilder.mark(); @SuppressWarnings("UnusedDeclaration") PsiBuilder.Marker m1 = myBuilder.mark(); myBuilder.getTokenType(); myBuilder.advanceLexer(); try { m.done(JavaTokenType.PACKAGE_KEYWORD); fail("Assertion must fire"); } catch (AssertionFailedError e) { throw e; } catch (Throwable e) { if (!e.getMessage().startsWith("Another not done marker")) { fail("Wrong assertion message"); } } } public void testNotAllTokensProcessed() { myBuilder = createBuilder("foo"); myBuilder.setDebugMode(true); final PsiBuilder.Marker m = myBuilder.mark(); m.done(JavaTokenType.PACKAGE_KEYWORD); try { myBuilder.getTreeBuilt(); fail("Assertion must fire"); } catch (AssertionFailedError e) { throw e; } catch (Throwable e) { if (!e.getMessage().startsWith("Tokens [IDENTIFIER] were not inserted into the tree")) { fail("Wrong assertion message"); } } } public void testMergeWhenEmptyElementAfterWhitespaceIsLastChild() throws Throwable { myBuilder = createBuilder(" foo bar"); parseWhenEmptyElementAfterWhitespaceIsLastChild(); final ASTNode tree = myBuilder.getTreeBuilt(); new DummyHolder(getPsiManager(), (TreeElement)tree, null); myBuilder = createBuilder(" bar", tree); parseWhenEmptyElementAfterWhitespaceIsLastChild(); DebugUtil.startPsiModification(null); try { myBuilder.getTreeBuilt(); fail(); } catch (BlockSupport.ReparsedSuccessfullyException e) { e.getDiffLog().performActualPsiChange(tree.getPsi().getContainingFile()); } finally { DebugUtil.finishPsiModification(); } assertEquals(" bar", tree.getText()); } private void parseWhenEmptyElementAfterWhitespaceIsLastChild() { final PsiBuilder.Marker root = myBuilder.mark(); final PsiBuilder.Marker composite = myBuilder.mark(); final PsiBuilder.Marker backup = myBuilder.mark(); if ("foo".equals(myBuilder.getTokenText())) { myBuilder.advanceLexer(); myBuilder.getTokenType(); myBuilder.mark().done(JavaStubElementTypes.TYPE_PARAMETER_LIST); backup.done(JavaStubElementTypes.ANNOTATION_METHOD); } else { backup.rollbackTo(); } composite.done(JavaStubElementTypes.ANONYMOUS_CLASS); myBuilder.getTokenType(); myBuilder.advanceLexer(); root.done(JavaStubElementTypes.ENUM_CONSTANT_INITIALIZER); } }