/* * Copyright 2013-2017 consulo.io * * 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 consulo.csharp.ide.completion.patterns; import com.intellij.patterns.PatternCondition; import com.intellij.patterns.PsiElementPattern; import com.intellij.patterns.StandardPatterns; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiErrorElement; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.ProcessingContext; import consulo.annotation.access.RequiredReadAction; import consulo.csharp.lang.psi.*; import consulo.csharp.lang.psi.impl.source.CSharpConstructorSuperCallImpl; import consulo.csharp.lang.psi.impl.source.CSharpExpressionStatementImpl; import consulo.csharp.lang.psi.impl.source.CSharpPsiUtilImpl; import consulo.dotnet.psi.DotNetType; import javax.annotation.Nonnull; /** * @author VISTALL * @since 01.08.2015 */ public class CSharpPatterns { @Nonnull public static PsiElementPattern.Capture<PsiElement> expressionStart() { return StandardPatterns.psiElement(CSharpTokens.IDENTIFIER).withParent(CSharpReferenceExpressionEx.class).with(new PatternCondition<PsiElement>("error validator") { @Override public boolean accepts(@Nonnull PsiElement element, ProcessingContext processingContext) { CSharpReferenceExpression expression = PsiTreeUtil.getParentOfType(element, CSharpReferenceExpression.class); assert expression != null; PsiElement parent = expression.getParent(); if(parent instanceof CSharpCallArgument) { PsiElement temp = UsefulPsiTreeUtil.getPrevSiblingSkipWhiteSpaces(parent, true); if(temp instanceof PsiErrorElement) { return false; } temp = UsefulPsiTreeUtil.getNextSiblingSkippingWhiteSpacesAndComments(parent); if(temp instanceof PsiErrorElement) { return false; } } else if(parent instanceof CSharpConstructorSuperCallImpl) { return false; } return true; } }); } @Nonnull public static PsiElementPattern.Capture<PsiElement> statementStart() { return StandardPatterns.psiElement().withElementType(CSharpTokens.IDENTIFIER).with(new PatternCondition<PsiElement>("statement-validator") { @Override @RequiredReadAction public boolean accepts(@Nonnull PsiElement element, ProcessingContext processingContext) { PsiElement parent = element.getParent(); PsiElement parent2 = parent == null ? null : parent.getParent(); PsiElement parent3 = parent2 == null ? null : parent2.getParent(); if(parent3 instanceof CSharpLocalVariable) { return validateLocalVariable((CSharpLocalVariable) parent3); } if(parent instanceof CSharpReferenceExpression && parent2 instanceof CSharpExpressionStatementImpl) { return validateReferenceExpression((CSharpReferenceExpression) parent); } return false; } @RequiredReadAction private boolean validateReferenceExpression(CSharpReferenceExpression expression) { if(expression.getQualifier() != null) { return false; } CSharpReferenceExpression.ResolveToKind kind = expression.kind(); return kind == CSharpReferenceExpression.ResolveToKind.ANY_MEMBER; } @RequiredReadAction private boolean validateLocalVariable(CSharpLocalVariable localVariable) { // we cant use it when 'const <exp>' if(localVariable == null || localVariable.isConstant()) { return false; } // disable it inside non local decl statement, like catch if(!(localVariable.getParent() instanceof CSharpLocalVariableDeclarationStatement)) { return false; } DotNetType type = localVariable.getType(); if(!(type instanceof CSharpUserType)) { return false; } CSharpReferenceExpression referenceExpression = ((CSharpUserType) type).getReferenceExpression(); if(referenceExpression.getQualifier() != null) { return false; } return CSharpPsiUtilImpl.isNullOrEmpty(localVariable); } }); /*return StandardPatterns.psiElement().withElementType(CSharpTokens.IDENTIFIER).withSuperParent(3, CSharpLocalVariable.class).with(new PatternCondition<PsiElement> ("null-identifier-local-var") { @Override @RequiredReadAction public boolean accepts(@NotNull PsiElement element, ProcessingContext context) { CSharpLocalVariable localVariable = PsiTreeUtil.getParentOfType(element, CSharpLocalVariable.class); // we cant use it when 'const <exp>' if(localVariable == null || localVariable.isConstant()) { return false; } // disable it inside non local decl statement, like catch if(!(localVariable.getParent() instanceof CSharpLocalVariableDeclarationStatement)) { return false; } DotNetType type = localVariable.getType(); if(!(type instanceof CSharpUserType)) { return false; } CSharpReferenceExpression referenceExpression = ((CSharpUserType) type).getReferenceExpression(); if(referenceExpression.getQualifier() != null) { return false; } return CSharpPsiUtilImpl.isNullOrEmpty(localVariable); } }); */ } @Nonnull public static PsiElementPattern.Capture<PsiElement> fieldStart() { return StandardPatterns.psiElement().withElementType(CSharpTokens.IDENTIFIER).withSuperParent(3, CSharpFieldDeclaration.class).with(new PatternCondition<PsiElement>("field-type-no-qualifier") { @Override @RequiredReadAction public boolean accepts(@Nonnull PsiElement element, ProcessingContext context) { CSharpFieldDeclaration declaration = PsiTreeUtil.getParentOfType(element, CSharpFieldDeclaration.class); if(declaration == null) { return false; } DotNetType type = declaration.getType(); if(!(type instanceof CSharpUserType)) { return false; } CSharpReferenceExpression referenceExpression = ((CSharpUserType) type).getReferenceExpression(); if(referenceExpression.getQualifier() != null) { return false; } return true; } }); } }