下面列出了com.intellij.psi.PsiRecursiveElementVisitor#com.intellij.psi.PsiErrorElement 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
private boolean hasErrorsInFile(@NotNull Document document) {
// We use the IntelliJ parser and look for syntax errors in the current document.
// We block reload if we find issues in the immediate file. We don't block reload if there
// are analysis issues in other files; the compilation errors from the flutter tool
// will indicate to the user where the problems are.
final PsiErrorElement firstError = ApplicationManager.getApplication().runReadAction((Computable<PsiErrorElement>)() -> {
final PsiFile psiFile = PsiDocumentManager.getInstance(myProject).getPsiFile(document);
if (psiFile instanceof DartFile) {
return PsiTreeUtil.findChildOfType(psiFile, PsiErrorElement.class, false);
}
else {
return null;
}
});
return firstError != null;
}
private boolean hasErrorsInFile(@NotNull Document document) {
// We use the IntelliJ parser and look for syntax errors in the current document.
// We block reload if we find issues in the immediate file. We don't block reload if there
// are analysis issues in other files; the compilation errors from the flutter tool
// will indicate to the user where the problems are.
final PsiErrorElement firstError = ApplicationManager.getApplication().runReadAction((Computable<PsiErrorElement>)() -> {
final PsiFile psiFile = PsiDocumentManager.getInstance(myProject).getPsiFile(document);
if (psiFile instanceof DartFile) {
return PsiTreeUtil.findChildOfType(psiFile, PsiErrorElement.class, false);
}
else {
return null;
}
});
return firstError != null;
}
@Override
public boolean shouldHighlightErrorElement(@NotNull PsiErrorElement error) {
final Project project = error.getProject();
final Language language = error.getLanguage();
// if ("CSS".equals(language.getID()) && PsiTreeUtil.getParentOfType(error, XmlAttribute.class) != null &&
// AngularIndexUtil.hasAngularJS(project)) {
// final PsiFile file = error.getContainingFile();
//
// PsiErrorElement nextError = error;
// while (nextError != null) {
// if (hasAngularInjectionAt(project, file, nextError.getTextOffset())) return false;
// nextError = PsiTreeUtil.getNextSiblingOfType(nextError, PsiErrorElement.class);
// }
// }
if (HTMLLanguage.INSTANCE.is(language) && error.getErrorDescription().endsWith("not closed")) {
System.out.println(error.getErrorDescription());
final PsiElement parent = error.getParent();
final XmlElementDescriptor descriptor = parent instanceof XmlTag ? ((XmlTag) parent).getDescriptor() : null;
return !(descriptor instanceof RTRequireTagDescriptor);
}
return true;
}
private int assertNoParsingErrors() {
final List<PsiErrorElement> errors = Lists.newLinkedList();
PsiFile file = getFile();
Assert.assertNotNull("File not found", file);
BashPsiUtils.visitRecursively(file, new BashVisitor() {
@Override
public void visitErrorElement(PsiErrorElement element) {
errors.add(element);
}
});
int count = errors.size();
if (count > 0) {
System.err.println(description(errors));
}
return count;
}
@Override
public boolean shouldHighlightErrorElement(@NotNull PsiErrorElement error) {
final Project project = error.getProject();
final Language language = error.getLanguage();
// if ("CSS".equals(language.getID()) && PsiTreeUtil.getParentOfType(error, XmlAttribute.class) != null &&
// AngularIndexUtil.hasAngularJS(project)) {
// final PsiFile file = error.getContainingFile();
//
// PsiErrorElement nextError = error;
// while (nextError != null) {
// if (hasAngularInjectionAt(project, file, nextError.getTextOffset())) return false;
// nextError = PsiTreeUtil.getNextSiblingOfType(nextError, PsiErrorElement.class);
// }
// }
if (HTMLLanguage.INSTANCE.is(language) && error.getErrorDescription().endsWith("not closed")) {
System.out.println(error.getErrorDescription());
final PsiElement parent = error.getParent();
final XmlElementDescriptor descriptor = parent instanceof XmlTag ? ((XmlTag) parent).getDescriptor() : null;
return !(descriptor instanceof RTRequireTagDescriptor);
}
return true;
}
public boolean shouldHighlightErrorElement(@NotNull PsiErrorElement element) {
PsiFile templateLanguageFile = PsiUtilCore.getTemplateLanguageFile(element.getContainingFile());
if (templateLanguageFile == null) {
return true;
}
Language language = templateLanguageFile.getLanguage();
if (language != LatteLanguage.INSTANCE) {
return true;
}
if (element.getParent() instanceof XmlElement || element.getParent() instanceof CssElement) {
return false;
}
if (element.getParent().getLanguage() == LatteLanguage.INSTANCE) {
return true;
}
PsiElement nextSibling;
for (nextSibling = PsiTreeUtil.nextLeaf(element); nextSibling instanceof PsiWhiteSpace; nextSibling = nextSibling.getNextSibling());
PsiElement psiElement = nextSibling == null ? null : PsiTreeUtil.findCommonParent(nextSibling, element);
boolean nextIsOuterLanguageElement = nextSibling instanceof OuterLanguageElement || nextSibling instanceof LatteMacroClassic;
return !nextIsOuterLanguageElement || psiElement == null || psiElement instanceof PsiFile;
}
@NotNull
public GLSLDeclaration[] getDeclarations() {
// convert the list of children to a list of GLSLStatement objects while performing sanity check.
PsiElement[] children = getChildren();
List<GLSLDeclaration> result = new ArrayList<>(children.length);
for (PsiElement child : children) {
if (child instanceof GLSLDeclaration) {
result.add((GLSLDeclaration) child);
} else if (!(child instanceof PsiErrorElement)) {
final ASTNode node = child.getNode();
if (node != null) {
final IElementType type = node.getElementType();
if (!GLSLTokenTypes.COMMENTS.contains(type)) {
Logger.getLogger("GLSLDeclarationList").warning("Parameter declaration list contains non-comment, non-expression element. ("+type+")");
}
}
}
}
return result.toArray(GLSLDeclaration.NO_DECLARATIONS);
}
@NotNull
@Override
public ASTNode getTreeBuilt() {
ASTNode built = super.getTreeBuilt();
if (LOG.isDebugEnabled() && !ApplicationManager.getApplication().isUnitTestMode()) {
// Walk the tree, depth first and print out all remaining error elements.
new ASTNodeWalker().walk(built, new Lambda<ASTNode>() {
@Override
public boolean process(ASTNode node) {
if (node instanceof PsiErrorElement) {
PsiErrorElement err = (PsiErrorElement)node;
printErrorInfo(err.getTextRange().getStartOffset(),
err.getText(),
err.getErrorDescription());
}
return true;
}
});
}
return built;
}
/**
* Twig tag pattern with some hack
* because we have invalid psi elements after STATEMENT_BLOCK_START
*
* {% <caret> %}
*/
public static ElementPattern<PsiElement> getTagTokenParserPattern() {
//noinspection unchecked
return PlatformPatterns
.psiElement()
.afterLeafSkipping(
PlatformPatterns.or(
PlatformPatterns.psiElement(PsiWhiteSpace.class),
PlatformPatterns.psiElement(TwigTokenTypes.WHITE_SPACE)
),
PlatformPatterns.or(
PlatformPatterns.psiElement(TwigTokenTypes.STATEMENT_BLOCK_START),
PlatformPatterns.psiElement(PsiErrorElement.class)
)
)
.beforeLeafSkipping(
PlatformPatterns.or(
PlatformPatterns.psiElement(PsiWhiteSpace.class),
PlatformPatterns.psiElement(TwigTokenTypes.WHITE_SPACE)
),
PlatformPatterns.psiElement(TwigTokenTypes.STATEMENT_BLOCK_END)
)
.withLanguage(TwigLanguage.INSTANCE);
}
@Override
public void visit(@Nonnull PsiElement element) {
if (element instanceof PsiErrorElement) {
if (myHighlightErrorElements) visitErrorElement((PsiErrorElement)element);
}
else {
if (myRunAnnotators) runAnnotators(element);
}
if (myAnnotationHolder.hasAnnotations()) {
for (Annotation annotation : myAnnotationHolder) {
myHolder.add(HighlightInfo.fromAnnotation(annotation, myBatchMode));
}
myAnnotationHolder.clear();
}
}
private static boolean hasErrorElements(@Nonnull final PsiElement element) {
if (element instanceof PsiErrorElement) {
HighlightErrorFilter[] errorFilters = Extensions.getExtensions(HighlightErrorFilter.EP_NAME, element.getProject());
for (HighlightErrorFilter errorFilter : errorFilters) {
if (!errorFilter.shouldHighlightErrorElement((PsiErrorElement)element)) {
return false;
}
}
return true;
}
for (PsiElement child : element.getChildren()) {
if (hasErrorElements(child)) {
return true;
}
}
return false;
}
@Override
public boolean hashCodesEqual(@Nonnull final ASTNode n1, @Nonnull final LighterASTNode n2) {
if (n1 instanceof LeafElement && n2 instanceof Token) {
boolean isForeign1 = n1 instanceof ForeignLeafPsiElement;
boolean isForeign2 = n2.getTokenType() instanceof ForeignLeafType;
if (isForeign1 != isForeign2) return false;
if (isForeign1) {
return StringUtil.equals(n1.getText(), ((ForeignLeafType)n2.getTokenType()).getValue());
}
return ((LeafElement)n1).textMatches(((Token)n2).getText());
}
if (n1 instanceof PsiErrorElement && n2.getTokenType() == TokenType.ERROR_ELEMENT) {
final PsiErrorElement e1 = (PsiErrorElement)n1;
if (!Comparing.equal(e1.getErrorDescription(), getErrorMessage(n2))) return false;
}
return ((TreeElement)n1).hc() == ((Node)n2).hc();
}
@Override
public int getNodeHash(PsiElement node) {
if (node == null) {
return 0;
}
if (node instanceof PsiWhiteSpace || node instanceof PsiErrorElement) {
return 0;
}
else if (node instanceof LeafElement) {
if (isToSkipAsLiteral(node)) {
return 0;
}
return node.getText().hashCode();
}
return node.getClass().getName().hashCode();
}
public static boolean isIgnoredNode(PsiElement element) {
// ex. "var i = 0" in AS: empty JSAttributeList should be skipped
/*if (element.getText().length() == 0) {
return true;
}*/
if (element instanceof PsiWhiteSpace || element instanceof PsiErrorElement || element instanceof PsiComment) {
return true;
}
if (!(element instanceof LeafElement)) {
return false;
}
if (CharArrayUtil.containsOnlyWhiteSpaces(element.getText())) {
return true;
}
EquivalenceDescriptorProvider descriptorProvider = EquivalenceDescriptorProvider.getInstance(element);
if (descriptorProvider == null) {
return false;
}
final IElementType elementType = ((LeafElement)element).getElementType();
return descriptorProvider.getIgnoredTokens().contains(elementType);
}
/**
* TODO if/when we implement alignment, update this method to do alignment properly
*
* This method handles indent and alignment on Enter.
*/
@NotNull
@Override
public ChildAttributes getChildAttributes(int newChildIndex) {
/**
* We indent if we're in a TAG_BLOCK (note that this works nicely since Enter can only be invoked
* INSIDE a block (i.e. after the open block).
*
* Also indent if we are wrapped in a block created by the templated language
*/
if (myNode.getElementType() == DustTypes.TAG_BLOCK
|| (getParent() instanceof DataLanguageBlockWrapper
&& (myNode.getElementType() != DustTypes.STATEMENTS || myNode.getTreeNext() instanceof PsiErrorElement))) {
return new ChildAttributes(Indent.getNormalIndent(), null);
} else {
return new ChildAttributes(Indent.getNoneIndent(), null);
}
}
/**
* Is the element have expected position in method parameters list
* and all previous parameters is valid
*/
private static boolean isParameterDepth(Object o, int depth) {
PsiElement[] parameters = ((ParameterList) ((PsiElement) o).getParent()).getParameters();
/* Если параметров меньше, чем необходимо - облом */
if (parameters.length < depth)
return false;
/* Все предыдущие параметры должны быть корректными */
if (depth > 1) for (int i = 0; i < depth; i++) {
if (parameters[i] instanceof PsiErrorElement)
return false;
}
/* Проверяем, что указанный параметр имеет правильную глубину вложенности */
return parameters[depth - 1].equals(o);
}
private void collectErrors(PsiElement psi) {
errors.addAll(
PsiUtils.findAllChildrenOfClassRecursive(psi, PsiErrorElement.class)
.stream()
.map(PsiErrorElement::getErrorDescription)
.collect(Collectors.toList()));
}
public static ScopeNode getContextFor(PsiElement element) {
PsiElement parent = element.getParent();
if ( parent instanceof ScopeNode ) {
return (ScopeNode)parent;
}
if ( parent instanceof PsiErrorElement ) {
return null;
}
return (ScopeNode)parent.getContext();
}
@Override
public boolean shouldHighlightErrorElement(@NotNull PsiErrorElement element) {
final PsiFile file = element.getContainingFile();
if(file instanceof JsonFile) {
if(Boolean.TRUE.equals(file.getVirtualFile().getUserData(JSGraphQLLanguageUIProjectService.IS_GRAPH_QL_VARIABLES_VIRTUAL_FILE))) {
// this is the variables file for GraphQL, so ignore errors as long as it's empty
return !file.getText().isEmpty();
}
}
return true;
}
/**
* @param node Tree node
* @return true if node is incomplete
*/
public boolean isIncomplete(@NotNull final ASTNode node) {
if (node.getElementType() instanceof ILazyParseableElementType) {
return false;
}
ASTNode lastChild = node.getLastChildNode();
while (lastChild != null &&
!(lastChild.getElementType() instanceof ILazyParseableElementType) &&
(lastChild.getPsi() instanceof PsiWhiteSpace || lastChild.getPsi() instanceof PsiComment)) {
lastChild = lastChild.getTreePrev();
}
return lastChild != null && (lastChild.getPsi() instanceof PsiErrorElement || isIncomplete(lastChild));
}
private String description(List<PsiErrorElement> errors) {
StringBuilder builder = new StringBuilder();
builder.append("\n## File: " + getFile().getName());
builder.append(", Errors: " + errors.size());
for (PsiErrorElement error : errors) {
builder.append("\n\t").append(error.getErrorDescription());
builder.append(": '").append(error.getText()).append("'").append(", line ").append(BashPsiUtils.getElementLineNumber(error));
//builder.append(", column ").append(error.getTgetTextOffset());
}
builder.append("\n\n");
return builder.toString();
}
private void checkFileNesting(String filePath) {
PsiFile file = myFixture.configureByFile(filePath);
final List<PsiErrorElement> errors = Lists.newArrayList();
file.acceptChildren(new PsiElementVisitor() {
@Override
public void visitErrorElement(PsiErrorElement element) {
if (element.getErrorDescription().startsWith("Internal parser error")) {
errors.add(element);
}
}
});
Assert.assertEquals("Deep nesting must not trigger the recursion guard", 0, errors.size());
}
@Test
public void testEvalEcho() throws Exception {
PsiElement current = configurePsiAtCaret();
Assert.assertNotNull(current);
Assert.assertTrue("element is not a var: " + current, current instanceof BashVar);
Assert.assertNotNull("element is not in an eval block: " + current, PsiTreeUtil.getParentOfType(current, BashEvalBlock.class));
Assert.assertNull("File must not contain errors", PsiTreeUtil.findChildOfType(current.getContainingFile(), PsiErrorElement.class));
}
@Test
public void testEvalEcho2() throws Exception {
PsiElement current = configurePsiAtCaret();
Assert.assertNotNull(current);
Assert.assertTrue("element is not a eval block: " + current, current instanceof BashVar);
Assert.assertNotNull("element is not in an eval block: " + current, PsiTreeUtil.getParentOfType(current, BashEvalBlock.class));
Assert.assertNull("File must not contain errors", PsiTreeUtil.findChildOfType(current.getContainingFile(), PsiErrorElement.class));
}
@Test
@Ignore
public void _testEvalError() throws Exception {
PsiElement current = configurePsiAtCaret();
Assert.assertNotNull(current);
List<PsiErrorElement> errors = collectPsiErrors();
Assert.assertEquals("1 error needs to be found", 1, errors.size());
}
private List<PsiErrorElement> collectPsiErrors() {
final List<PsiErrorElement> errors = Lists.newLinkedList();
BashPsiUtils.visitRecursively(myFixture.getFile(), new BashVisitor() {
@Override
public void visitErrorElement(PsiErrorElement element) {
errors.add(element);
}
});
return errors;
}
@Override
protected boolean isInContext(PsiElement element) {
PsiElement topmostElement = XQueryPsiImplUtil.getTopmostElementWithTheSameOffset(element);
PsiElement topmostNonErrorElement = topmostElement instanceof PsiErrorElement
? topmostElement.getParent()
: topmostElement;
boolean isOnTheTopLevelOfTheStructure = topmostNonErrorElement.getParent() instanceof XQueryFile;
return isOnTheTopLevelOfTheStructure && isBeforeQueryBody(topmostElement) && isNotBeforeModuleDeclaration(topmostElement);
}
private void visitErrorElement(final PsiErrorElement element) {
for(HighlightErrorFilter errorFilter: myErrorFilters) {
if (!errorFilter.shouldHighlightErrorElement(element)) {
return;
}
}
HighlightInfo info = createErrorElementInfo(element);
myHolder.add(info);
}
private ThreeState textMatches(ASTNode oldNode, ASTNode newNode) {
myIndicator.checkCanceled();
String oldText = TreeUtil.isCollapsedChameleon(oldNode) ? oldNode.getText() : null;
String newText = TreeUtil.isCollapsedChameleon(newNode) ? newNode.getText() : null;
if (oldText != null && newText != null) return oldText.equals(newText) ? ThreeState.YES : ThreeState.UNSURE;
if (oldText != null) {
return compareTreeToText((TreeElement)newNode, oldText) ? ThreeState.YES : ThreeState.UNSURE;
}
if (newText != null) {
return compareTreeToText((TreeElement)oldNode, newText) ? ThreeState.YES : ThreeState.UNSURE;
}
if (oldNode instanceof ForeignLeafPsiElement) {
return newNode instanceof ForeignLeafPsiElement && oldNode.getText().equals(newNode.getText()) ? ThreeState.YES : ThreeState.NO;
}
if (newNode instanceof ForeignLeafPsiElement) return ThreeState.NO;
if (oldNode instanceof LeafElement) {
return ((LeafElement)oldNode).textMatches(newNode.getText()) ? ThreeState.YES : ThreeState.NO;
}
if (newNode instanceof LeafElement) {
return ((LeafElement)newNode).textMatches(oldNode.getText()) ? ThreeState.YES : ThreeState.NO;
}
if (oldNode instanceof PsiErrorElement && newNode instanceof PsiErrorElement) {
final PsiErrorElement e1 = (PsiErrorElement)oldNode;
final PsiErrorElement e2 = (PsiErrorElement)newNode;
if (!Comparing.equal(e1.getErrorDescription(), e2.getErrorDescription())) return ThreeState.NO;
}
return ThreeState.UNSURE;
}
@Override
public boolean hashCodesEqual(@Nonnull final ASTNode n1, @Nonnull final ASTNode n2) {
if (n1 instanceof LeafElement && n2 instanceof LeafElement) {
return textMatches(n1, n2) == ThreeState.YES;
}
if (n1 instanceof PsiErrorElement && n2 instanceof PsiErrorElement) {
final PsiErrorElement e1 = (PsiErrorElement)n1;
final PsiErrorElement e2 = (PsiErrorElement)n2;
if (!Comparing.equal(e1.getErrorDescription(), e2.getErrorDescription())) return false;
}
return ((TreeElement)n1).hc() == ((TreeElement)n2).hc();
}