Cleaner API for light token visiting

This commit is contained in:
Roman Shevchenko
2013-02-21 19:37:18 +01:00
parent a11720fd88
commit 5164e918d2
4 changed files with 77 additions and 111 deletions
@@ -18,8 +18,7 @@ package com.intellij.psi.impl.source;
import com.intellij.lang.ASTNode;
import com.intellij.lang.LighterAST;
import com.intellij.lang.LighterASTNode;
import com.intellij.lang.impl.ASTNodeBuilder;
import com.intellij.openapi.util.Ref;
import com.intellij.lang.LighterLazyParseableNode;
import com.intellij.psi.JavaTokenType;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiJavaFile;
@@ -33,11 +32,6 @@ import com.intellij.util.io.StringRef;
import org.jetbrains.annotations.NotNull;
public class JavaLightStubBuilder extends LightStubBuilder {
private static final TokenSet BLOCK_ELEMENTS = TokenSet.create(
JavaElementType.ANNOTATION, JavaElementType.CLASS, JavaElementType.ANONYMOUS_CLASS);
private static final TokenSet BLOCK_TOKENS = TokenSet.orSet(
TokenSet.create(JavaTokenType.AT), ElementType.CLASS_KEYWORD_BIT_SET);
@NotNull
@Override
protected StubElement createStubForFile(@NotNull PsiFile file, @NotNull LighterAST tree) {
@@ -61,29 +55,12 @@ public class JavaLightStubBuilder extends LightStubBuilder {
IElementType parentType = parent.getElementType();
IElementType nodeType = node.getElementType();
if (nodeType == JavaElementType.PARAMETER && parentType != JavaElementType.PARAMETER_LIST) {
return true;
}
if (nodeType == JavaElementType.PARAMETER_LIST && parentType == JavaElementType.LAMBDA_EXPRESSION) {
return true;
}
if (checkByTypes(parentType, nodeType)) return true;
if (nodeType == JavaElementType.CODE_BLOCK && node instanceof TreeElement) {
final Ref<Boolean> skip = Ref.create(true);
((TreeElement)node).acceptTree(new RecursiveTreeElementWalkingVisitor() {
@Override
protected void visitNode(TreeElement element) {
if (BLOCK_ELEMENTS.contains(element.getElementType())) {
skip.set(false);
stopWalking();
return;
}
super.visitNode(element);
}
});
return skip.get();
CodeBlockVisitor visitor = new CodeBlockVisitor();
((TreeElement)node).acceptTree(visitor);
return visitor.result;
}
return false;
@@ -94,6 +71,18 @@ public class JavaLightStubBuilder extends LightStubBuilder {
IElementType parentType = parent.getTokenType();
IElementType nodeType = node.getTokenType();
if (checkByTypes(parentType, nodeType)) return true;
if (nodeType == JavaElementType.CODE_BLOCK && node instanceof LighterLazyParseableNode) {
CodeBlockVisitor visitor = new CodeBlockVisitor();
((LighterLazyParseableNode)node).accept(visitor);
return visitor.result;
}
return false;
}
private static boolean checkByTypes(IElementType parentType, IElementType nodeType) {
if (nodeType == JavaElementType.PARAMETER && parentType != JavaElementType.PARAMETER_LIST) {
return true;
}
@@ -101,32 +90,44 @@ public class JavaLightStubBuilder extends LightStubBuilder {
return true;
}
if (nodeType == JavaElementType.CODE_BLOCK && node instanceof ASTNodeBuilder.ASTUnparsedNodeMarker) {
ASTNodeBuilder.ASTUnparsedNodeMarker nodeMarker = (ASTNodeBuilder.ASTUnparsedNodeMarker)node;
ASTNodeBuilder nodeBuilder = nodeMarker.getBuilder();
boolean seenNew = false, skip = true;
for (int i = nodeMarker.getStartLexemeIndex(), endIndex = nodeMarker.getEndLexemeIndex(); i < endIndex; ++i) {
IElementType type = nodeBuilder.getElementType(i);
if (type == JavaTokenType.NEW_KEYWORD) {
seenNew = true;
}
else if (seenNew && type == JavaTokenType.LBRACE) { // anonymous class
skip = false;
break;
}
else if (seenNew && type == JavaTokenType.SEMICOLON) {
seenNew = false;
}
else if (BLOCK_TOKENS.contains(type)) { // annotated local variables, type annotations, local classes
skip = false;
break;
}
}
return skip;
}
return false;
}
private static class CodeBlockVisitor extends RecursiveTreeElementWalkingVisitor implements LighterLazyParseableNode.Visitor {
private static final TokenSet BLOCK_ELEMENTS = TokenSet.create(
JavaElementType.ANNOTATION, JavaElementType.CLASS, JavaElementType.ANONYMOUS_CLASS);
private static final TokenSet BLOCK_TOKENS = TokenSet.orSet(
TokenSet.create(JavaTokenType.AT), ElementType.CLASS_KEYWORD_BIT_SET);
private boolean result = true;
private boolean seenNew = false;
@Override
protected void visitNode(TreeElement element) {
if (BLOCK_ELEMENTS.contains(element.getElementType())) {
result = false;
stopWalking();
return;
}
super.visitNode(element);
}
@Override
public boolean visit(IElementType type) {
if (type == JavaTokenType.NEW_KEYWORD) {
seenNew = true;
}
else if (seenNew && type == JavaTokenType.LBRACE) { // anonymous class
result = false;
}
else if (seenNew && type == JavaTokenType.SEMICOLON) {
seenNew = false;
}
else if (BLOCK_TOKENS.contains(type)) { // annotated local variables, type annotations, local classes
result = false;
}
return result;
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2010 JetBrains s.r.o.
* 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.
@@ -16,7 +16,9 @@
package com.intellij.lang;
import com.intellij.psi.PsiFile;
import com.intellij.psi.tree.IElementType;
import com.intellij.util.CharTable;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public interface LighterLazyParseableNode extends LighterASTNode {
@@ -26,4 +28,10 @@ public interface LighterLazyParseableNode extends LighterASTNode {
CharTable getCharTable();
CharSequence getText();
interface Visitor {
boolean visit(IElementType type);
}
boolean accept(@NotNull Visitor visitor);
}
@@ -1,34 +0,0 @@
/*
* Copyright 2000-2012 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.impl;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.Nullable;
/**
* @author Maxim.Mossienko
* @since 5.11.2011
*/
public interface ASTNodeBuilder {
@Nullable
IElementType getElementType(int lexemeIndex);
interface ASTUnparsedNodeMarker {
ASTNodeBuilder getBuilder();
int getStartLexemeIndex();
int getEndLexemeIndex();
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
* 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.
@@ -61,7 +61,7 @@ import java.util.Map;
/**
* @author max
*/
public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder, ASTNodeBuilder {
public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder {
private static final Logger LOG = Logger.getInstance("#com.intellij.lang.impl.PsiBuilderImpl");
// function stored in PsiBuilderImpl' user data which called during reparse when merge algorithm is not sure what to merge
@@ -268,11 +268,6 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder, AS
public abstract int hc();
}
@Override
public IElementType getElementType(int lexemeIndex) {
return lexemeIndex < myLexemeCount && lexemeIndex >= 0 ? myLexTypes[lexemeIndex] : null;
}
public abstract static class ProductionMarker extends Node {
protected int myLexemeIndex;
protected WhitespacesAndCommentsBinder myEdgeTokenBinder;
@@ -521,7 +516,7 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder, AS
private static class TokenNode extends Token implements LighterASTTokenNode {
}
private static class LazyParseableToken extends Token implements LighterLazyParseableNode, ASTUnparsedNodeMarker {
private static class LazyParseableToken extends Token implements LighterLazyParseableNode {
private MyTreeStructure myParent;
private FlyweightCapableTreeStructure<LighterASTNode> myParsed;
private int myStartIndex;
@@ -552,20 +547,16 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder, AS
}
@Override
public ASTNodeBuilder getBuilder() {
return myBuilder;
}
public boolean accept(@NotNull Visitor visitor) {
for (int i = myStartIndex; i < myEndIndex; i++) {
IElementType type = myBuilder.myLexTypes[i];
if (!visitor.visit(type)) {
return false;
}
}
@Override
public int getStartLexemeIndex() {
return myStartIndex;
return true;
}
@Override
public int getEndLexemeIndex() {
return myEndIndex;
}
}
private static class DoneMarker extends ProductionMarker {
@@ -1341,7 +1332,7 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder, AS
boolean oldIsErrorElement = oldNode instanceof PsiErrorElement;
boolean newIsErrorElement = newNode.getTokenType() == TokenType.ERROR_ELEMENT;
if (oldIsErrorElement != newIsErrorElement) return ThreeState.NO;
if (oldIsErrorElement && newIsErrorElement) {
if (oldIsErrorElement) {
final PsiErrorElement e1 = (PsiErrorElement)oldNode;
return Comparing.equal(e1.getErrorDescription(), getErrorMessage(newNode)) ? ThreeState.UNSURE : ThreeState.NO;
}
@@ -1421,7 +1412,7 @@ public class PsiBuilderImpl extends UserDataHolderBase implements PsiBuilder, AS
boolean isForeign2 = n2.getTokenType() instanceof ForeignLeafType;
if (isForeign1 != isForeign2) return false;
if (isForeign1 && isForeign2) {
if (isForeign1) {
return n1.getText().equals(((ForeignLeafType)n2.getTokenType()).getValue());
}