blob: 418bc06d3b9eafa7ffb47c8645669b59ca76c9dd [file] [log] [blame]
package com.intellij.structuralsearch.impl.matcher;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.javadoc.PsiDocComment;
import com.intellij.psi.javadoc.PsiDocTag;
import com.intellij.psi.javadoc.PsiDocTagValue;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.structuralsearch.MatchOptions;
import com.intellij.structuralsearch.MatchResult;
import com.intellij.structuralsearch.impl.matcher.filters.LexicalNodesFilter;
import com.intellij.structuralsearch.impl.matcher.handlers.MatchPredicate;
import com.intellij.structuralsearch.impl.matcher.handlers.MatchingHandler;
import com.intellij.structuralsearch.impl.matcher.handlers.SubstitutionHandler;
import com.intellij.dupLocator.iterators.ArrayBackedNodeIterator;
import com.intellij.structuralsearch.impl.matcher.iterators.DocValuesIterator;
import com.intellij.structuralsearch.impl.matcher.iterators.HierarchyNodeIterator;
import com.intellij.dupLocator.iterators.NodeIterator;
import com.intellij.structuralsearch.impl.matcher.predicates.NotPredicate;
import com.intellij.structuralsearch.impl.matcher.predicates.RegExpPredicate;
import com.intellij.util.containers.ContainerUtil;
import java.util.*;
/**
* @author Eugene.Kudelevsky
*/
public class JavaMatchingVisitor extends JavaElementVisitor {
public static final String[] MODIFIERS = {
PsiModifier.PUBLIC, PsiModifier.PROTECTED, PsiModifier.PRIVATE, PsiModifier.STATIC, PsiModifier.ABSTRACT, PsiModifier.FINAL,
PsiModifier.NATIVE, PsiModifier.SYNCHRONIZED, PsiModifier.STRICTFP, PsiModifier.TRANSIENT, PsiModifier.VOLATILE, PsiModifier.DEFAULT
};
public static final Key<List<PsiCatchSection>> UNMATCHED_CATCH_SECTION_CONTENT_VAR_KEY = Key.create("UnmatchedCatchSection");
private final GlobalMatchingVisitor myMatchingVisitor;
private PsiClass myClazz;
static {
Arrays.sort(MODIFIERS);
}
public JavaMatchingVisitor(GlobalMatchingVisitor matchingVisitor) {
this.myMatchingVisitor = matchingVisitor;
}
@Override
public void visitComment(PsiComment comment) {
PsiElement comment2 = null;
if (!(myMatchingVisitor.getElement() instanceof PsiComment)) {
if (myMatchingVisitor.getElement() instanceof PsiMember) {
final PsiElement[] children = myMatchingVisitor.getElement().getChildren();
if (children[0] instanceof PsiComment) {
comment2 = children[0];
}
}
}
else {
comment2 = myMatchingVisitor.getElement();
}
if (comment2 == null) {
myMatchingVisitor.setResult(false);
return;
}
final Object userData = comment.getUserData(CompiledPattern.HANDLER_KEY);
if (userData instanceof String) {
String str = (String)userData;
int end = comment2.getTextLength();
if (((PsiComment)comment2).getTokenType() == JavaTokenType.C_STYLE_COMMENT) {
end -= 2;
}
myMatchingVisitor.setResult(((SubstitutionHandler)myMatchingVisitor.getMatchContext().getPattern().getHandler(str)).handle(
comment2,
2,
end,
myMatchingVisitor.getMatchContext()
));
}
else if (userData instanceof MatchingHandler) {
myMatchingVisitor.setResult(((MatchingHandler)userData).match(comment, comment2, myMatchingVisitor.getMatchContext()));
}
else {
myMatchingVisitor.setResult(comment.getText().equals(comment2.getText()));
}
}
private static boolean isNotInstanceModifier(final PsiModifierList list2) {
return list2.hasModifierProperty(PsiModifier.STATIC) ||
list2.hasModifierProperty(PsiModifier.ABSTRACT);
}
@Override
public final void visitModifierList(final PsiModifierList list) {
final PsiModifierList list2 = (PsiModifierList)myMatchingVisitor.getElement();
for (@PsiModifier.ModifierConstant String modifier : MODIFIERS) {
if (list.hasModifierProperty(modifier) && !list2.hasModifierProperty(modifier)) {
myMatchingVisitor.setResult(false);
return;
}
}
final PsiAnnotation[] annotations = list.getAnnotations();
if (annotations.length > 0) {
HashSet<PsiAnnotation> set = new HashSet<PsiAnnotation>(Arrays.asList(annotations));
for (PsiAnnotation annotation : annotations) {
final PsiJavaCodeReferenceElement nameReferenceElement = annotation.getNameReferenceElement();
if (nameReferenceElement != null && MatchOptions.MODIFIER_ANNOTATION_NAME.equals(nameReferenceElement.getText())) {
final PsiAnnotationParameterList parameterList = annotation.getParameterList();
final PsiNameValuePair[] attributes = parameterList.getAttributes();
for (PsiNameValuePair pair : attributes) {
final PsiAnnotationMemberValue value = pair.getValue();
if (value == null) continue;
if (value instanceof PsiArrayInitializerMemberValue) {
boolean matchedOne = false;
for (PsiAnnotationMemberValue v : ((PsiArrayInitializerMemberValue)value).getInitializers()) {
@PsiModifier.ModifierConstant String name = StringUtil.stripQuotesAroundValue(v.getText());
if (MatchOptions.INSTANCE_MODIFIER_NAME.equals(name)) {
if (isNotInstanceModifier(list2)) {
myMatchingVisitor.setResult(false);
return;
}
else {
matchedOne = true;
}
}
else if (list2.hasModifierProperty(name)) {
matchedOne = true;
break;
}
}
if (!matchedOne) {
myMatchingVisitor.setResult(false);
return;
}
}
else {
@PsiModifier.ModifierConstant String name = StringUtil.stripQuotesAroundValue(value.getText());
if (MatchOptions.INSTANCE_MODIFIER_NAME.equals(name)) {
if (isNotInstanceModifier(list2)) {
myMatchingVisitor.setResult(false);
return;
}
}
else if (!list2.hasModifierProperty(name)) {
myMatchingVisitor.setResult(false);
return;
}
}
}
set.remove(annotation);
}
}
myMatchingVisitor.setResult(set.isEmpty() || myMatchingVisitor
.matchInAnyOrder(set.toArray(new PsiAnnotation[set.size()]), list2.getAnnotations()));
}
else {
myMatchingVisitor.setResult(true);
}
}
@Override
public void visitDocTag(final PsiDocTag tag) {
final PsiDocTag tag2 = (PsiDocTag)myMatchingVisitor.getElement();
final boolean isTypedVar = myMatchingVisitor.getMatchContext().getPattern().isTypedVar(tag.getNameElement());
myMatchingVisitor.setResult(isTypedVar || tag.getName().equals(tag2.getName()));
PsiElement psiDocTagValue = tag.getValueElement();
boolean isTypedValue = false;
if (myMatchingVisitor.getResult() && psiDocTagValue != null) {
final PsiElement[] children = psiDocTagValue.getChildren();
if (children.length == 1) {
psiDocTagValue = children[0];
}
isTypedValue = myMatchingVisitor.getMatchContext().getPattern().isTypedVar(psiDocTagValue);
if (isTypedValue) {
if (tag2.getValueElement() != null) {
myMatchingVisitor.setResult(myMatchingVisitor.handleTypedElement(psiDocTagValue, tag2.getValueElement()));
}
else {
myMatchingVisitor.setResult(allowsAbsenceOfMatch(psiDocTagValue));
}
}
}
if (myMatchingVisitor.getResult() && !isTypedValue) {
myMatchingVisitor.setResult(myMatchingVisitor.matchInAnyOrder(
new DocValuesIterator(tag.getFirstChild()),
new DocValuesIterator(tag2.getFirstChild())
));
}
if (myMatchingVisitor.getResult() && isTypedVar) {
myMatchingVisitor.setResult(myMatchingVisitor.handleTypedElement(tag.getNameElement(), tag2.getNameElement()));
}
}
private boolean allowsAbsenceOfMatch(final PsiElement element) {
MatchingHandler handler = myMatchingVisitor.getMatchContext().getPattern().getHandler(element);
if (handler instanceof SubstitutionHandler &&
((SubstitutionHandler)handler).getMinOccurs() == 0) {
return true;
}
return false;
}
@Override
public void visitDocComment(final PsiDocComment comment) {
PsiDocComment comment2;
if (myMatchingVisitor.getElement() instanceof PsiDocCommentOwner) {
comment2 = ((PsiDocCommentOwner)myMatchingVisitor.getElement()).getDocComment();
if (comment2 == null) {
// doc comment are not collapsed for inner classes!
myMatchingVisitor.setResult(false);
return;
}
}
else {
comment2 = (PsiDocComment)myMatchingVisitor.getElement();
if (myMatchingVisitor.getElement().getParent() instanceof PsiDocCommentOwner) {
myMatchingVisitor.setResult(false);
return; // we should matched the doc before
}
}
if (comment.getTags().length > 0) {
myMatchingVisitor.setResult(myMatchingVisitor.matchInAnyOrder(comment.getTags(), comment2.getTags()));
}
else {
visitComment(comment);
}
}
@Override
public void visitElement(PsiElement el) {
myMatchingVisitor.setResult(el.textMatches(myMatchingVisitor.getElement()));
}
@Override
public void visitArrayInitializerExpression(PsiArrayInitializerExpression expression) {
final PsiArrayInitializerExpression expr2 = (PsiArrayInitializerExpression)myMatchingVisitor.getElement();
myMatchingVisitor.setResult(myMatchingVisitor.matchSequentially(
new ArrayBackedNodeIterator(expression.getInitializers()),
new ArrayBackedNodeIterator(expr2.getInitializers())
));
}
@Override
public void visitClassInitializer(PsiClassInitializer initializer) {
PsiClassInitializer initializer2 = (PsiClassInitializer)myMatchingVisitor.getElement();
myMatchingVisitor.setResult(myMatchingVisitor.match(initializer.getModifierList(), initializer2.getModifierList()) &&
myMatchingVisitor.match(initializer.getBody(), initializer2.getBody()));
}
@Override
public void visitCodeBlock(PsiCodeBlock block) {
myMatchingVisitor.setResult(myMatchingVisitor.matchSons(block, myMatchingVisitor.getElement()));
}
@Override
public void visitJavaToken(final PsiJavaToken token) {
PsiElement element = myMatchingVisitor.getElement();
boolean result;
if (!(element instanceof PsiJavaToken)) {
result = token.textMatches(element);
} else {
final PsiJavaToken anotherToken = (PsiJavaToken)element;
result = token.getTokenType() == anotherToken.getTokenType() && token.textMatches(anotherToken);
}
myMatchingVisitor.setResult(result);
}
@Override
public void visitAnnotation(PsiAnnotation annotation) {
final PsiAnnotation psiAnnotation = (PsiAnnotation)myMatchingVisitor.getElement();
myMatchingVisitor.setResult(myMatchingVisitor.match(annotation.getNameReferenceElement(), psiAnnotation.getNameReferenceElement()) &&
myMatchingVisitor
.matchInAnyOrder(annotation.getParameterList().getAttributes(),
psiAnnotation.getParameterList().getAttributes()));
}
@Override
public void visitNameValuePair(PsiNameValuePair pair) {
final PsiIdentifier nameIdentifier = pair.getNameIdentifier();
final PsiNameValuePair elementNameValuePair = (PsiNameValuePair)myMatchingVisitor.getElement();
final PsiIdentifier otherIdentifier = elementNameValuePair.getNameIdentifier();
final PsiAnnotationMemberValue annotationInitializer = pair.getValue();
if (annotationInitializer != null) {
final boolean isTypedInitializer = myMatchingVisitor.getMatchContext().getPattern().isTypedVar(annotationInitializer) &&
annotationInitializer instanceof PsiReferenceExpression;
myMatchingVisitor.setResult(myMatchingVisitor.match(annotationInitializer, elementNameValuePair.getValue()) ||
(isTypedInitializer &&
elementNameValuePair.getValue() == null &&
allowsAbsenceOfMatch(annotationInitializer)
));
}
if (myMatchingVisitor.getResult()) {
final MatchingHandler handler = myMatchingVisitor.getMatchContext().getPattern().getHandler(nameIdentifier);
if (handler instanceof SubstitutionHandler) {
myMatchingVisitor.setResult(((SubstitutionHandler)handler).handle(otherIdentifier, myMatchingVisitor.getMatchContext()));
}
else if (nameIdentifier != null) {
myMatchingVisitor.setResult(myMatchingVisitor.match(nameIdentifier, otherIdentifier));
}
else {
myMatchingVisitor.setResult(otherIdentifier == null || otherIdentifier.getText().equals("value"));
}
}
}
private boolean checkHierarchy(PsiMember element, PsiMember patternElement) {
final MatchingHandler handler = myMatchingVisitor.getMatchContext().getPattern().getHandler(patternElement);
if (handler instanceof SubstitutionHandler) {
final SubstitutionHandler handler2 = (SubstitutionHandler)handler;
if (!handler2.isSubtype()) {
if (handler2.isStrictSubtype()) {
// check if element is declared not in current class (in ancestors)
return element.getContainingClass() != myClazz;
}
}
else {
return true;
}
}
// check if element is declared in current class (not in ancestors)
return element.getContainingClass() == myClazz;
}
@Override
public void visitField(PsiField psiField) {
if (!checkHierarchy((PsiField)myMatchingVisitor.getElement(), psiField)) {
myMatchingVisitor.setResult(false);
return;
}
super.visitField(psiField);
}
@Override
public void visitAnonymousClass(final PsiAnonymousClass clazz) {
final PsiAnonymousClass clazz2 = (PsiAnonymousClass)myMatchingVisitor.getElement();
final boolean isTypedVar = myMatchingVisitor.getMatchContext().getPattern().isTypedVar(clazz.getFirstChild());
myMatchingVisitor.setResult((myMatchingVisitor.match(clazz.getBaseClassReference(), clazz2.getBaseClassReference()) || isTypedVar) &&
myMatchingVisitor.matchSons(clazz.getArgumentList(), clazz2.getArgumentList()) &&
compareClasses(clazz, clazz2));
if (myMatchingVisitor.getResult() && isTypedVar) {
myMatchingVisitor.setResult(myMatchingVisitor.handleTypedElement(clazz.getFirstChild(), clazz2.getFirstChild()));
}
}
@Override
public void visitLambdaExpression(PsiLambdaExpression expression) {
final PsiLambdaExpression expression2 = (PsiLambdaExpression)myMatchingVisitor.getElement();
boolean result = true;
final PsiParameterList parameterList1 = expression.getParameterList();
if (parameterList1.getParametersCount() != 0) {
result = myMatchingVisitor.matchSons(parameterList1, expression2.getParameterList());
}
final PsiElement body1 = getElementToMatch(expression.getBody());
if (body1 != null) {
result = myMatchingVisitor.matchSequentially(body1, getElementToMatch(expression2.getBody()));
}
myMatchingVisitor.setResult(result);
}
private static PsiElement getElementToMatch(PsiElement element) {
if (element instanceof PsiCodeBlock) {
element = PsiTreeUtil.getChildOfAnyType(element, PsiStatement.class, PsiComment.class);
}
if (element instanceof PsiExpressionStatement) {
element = ((PsiExpressionStatement)element).getExpression();
}
if (element instanceof PsiReturnStatement) {
element = ((PsiReturnStatement)element).getReturnValue();
}
return element;
}
protected boolean matchInAnyOrder(final PsiReferenceList elements, final PsiReferenceList elements2, GlobalMatchingVisitor visitor) {
if ((elements == null && visitor.isLeftLooseMatching()) ||
elements == elements2 // null
) {
return true;
}
return visitor.matchInAnyOrder(
elements.getReferenceElements(),
(elements2 != null) ? elements2.getReferenceElements() : PsiElement.EMPTY_ARRAY
);
}
private boolean compareClasses(final PsiClass clazz, final PsiClass clazz2) {
final PsiClass saveClazz = this.myClazz;
final MatchContext.MatchedElementsListener oldListener = myMatchingVisitor.getMatchContext().getMatchedElementsListener();
this.myClazz = clazz2;
final CompiledPattern pattern = myMatchingVisitor.getMatchContext().getPattern();
assert pattern instanceof JavaCompiledPattern;
final JavaCompiledPattern javaPattern = (JavaCompiledPattern)pattern;
final String unmatchedHandlerName = clazz.getUserData(JavaCompiledPattern.ALL_CLASS_CONTENT_VAR_NAME_KEY);
final MatchingHandler allRemainingClassContentElementHandler = unmatchedHandlerName != null ? pattern.getHandler(unmatchedHandlerName) : null;
MatchContext.MatchedElementsListener newListener = null;
assert javaPattern instanceof JavaCompiledPattern;
if (allRemainingClassContentElementHandler != null) {
myMatchingVisitor.getMatchContext().setMatchedElementsListener(
newListener = new MatchContext.MatchedElementsListener() {
private Set<PsiElement> myMatchedElements;
public void matchedElements(Collection<PsiElement> matchedElements) {
if (matchedElements == null) return;
if (myMatchedElements == null) {
myMatchedElements = new HashSet<PsiElement>(matchedElements);
}
else {
myMatchedElements.addAll(matchedElements);
}
}
public void commitUnmatched() {
final SubstitutionHandler handler = (SubstitutionHandler)allRemainingClassContentElementHandler;
for (PsiElement el = clazz2.getFirstChild(); el != null; el = el.getNextSibling()) {
if (el instanceof PsiMember && (myMatchedElements == null || !myMatchedElements.contains(el))) {
handler.handle(el, myMatchingVisitor.getMatchContext());
}
}
}
}
);
}
boolean result = false;
try {
final boolean templateIsInterface = clazz.isInterface();
if (templateIsInterface != clazz2.isInterface()) return false;
if (templateIsInterface && clazz.isAnnotationType() && !clazz2.isAnnotationType()) return false;
final boolean templateIsEnum = clazz.isEnum();
if (templateIsEnum && !clazz2.isEnum()) return false;
if (!matchInAnyOrder(clazz.getExtendsList(), clazz2.getExtendsList(), myMatchingVisitor)) {
return false;
}
// check if implements is in extended classes implements
final PsiReferenceList implementsList = clazz.getImplementsList();
if (implementsList != null) {
if (!matchInAnyOrder(implementsList, clazz2.getImplementsList(), myMatchingVisitor)) {
final PsiReferenceList anotherExtendsList = clazz2.getExtendsList();
final PsiJavaCodeReferenceElement[] referenceElements = implementsList.getReferenceElements();
boolean accepted = false;
if (referenceElements.length > 0 && anotherExtendsList != null) {
final HierarchyNodeIterator iterator = new HierarchyNodeIterator(clazz2, true, true, false);
accepted = myMatchingVisitor.matchInAnyOrder(new ArrayBackedNodeIterator(referenceElements), iterator);
}
if (!accepted) return false;
}
}
final PsiField[] fields = clazz.getFields();
if (fields.length > 0) {
final PsiField[] fields2 = javaPattern.isRequestsSuperFields() ?
clazz2.getAllFields() :
clazz2.getFields();
if (!myMatchingVisitor.matchInAnyOrder(fields, fields2)) {
return false;
}
}
final PsiMethod[] methods = clazz.getMethods();
if (methods.length > 0) {
final PsiMethod[] methods2 = javaPattern.isRequestsSuperMethods() ?
clazz2.getAllMethods() :
clazz2.getMethods();
if (!myMatchingVisitor.matchInAnyOrder(methods, methods2)) {
return false;
}
}
final PsiClass[] nestedClasses = clazz.getInnerClasses();
if (nestedClasses.length > 0) {
final PsiClass[] nestedClasses2 = javaPattern.isRequestsSuperInners() ?
clazz2.getAllInnerClasses() :
clazz2.getInnerClasses();
if (!myMatchingVisitor.matchInAnyOrder(nestedClasses, nestedClasses2)) {
return false;
}
}
final PsiClassInitializer[] initializers = clazz.getInitializers();
if (initializers.length > 0) {
final PsiClassInitializer[] initializers2 = clazz2.getInitializers();
if (!myMatchingVisitor.matchInAnyOrder(initializers, initializers2)) {
return false;
}
}
result = true;
return result;
}
finally {
if (result && newListener != null) newListener.commitUnmatched();
this.myClazz = saveClazz;
myMatchingVisitor.getMatchContext().setMatchedElementsListener(oldListener);
}
}
private boolean compareBody(final PsiElement el1, final PsiElement el2) {
PsiElement compareElement1 = el1;
PsiElement compareElement2 = el2;
if (myMatchingVisitor.getMatchContext().getOptions().isLooseMatching()) {
if (el1 instanceof PsiBlockStatement) {
compareElement1 = ((PsiBlockStatement)el1).getCodeBlock().getFirstChild();
}
if (el2 instanceof PsiBlockStatement) {
compareElement2 = ((PsiBlockStatement)el2).getCodeBlock().getFirstChild();
}
}
return myMatchingVisitor.matchSequentially(compareElement1, compareElement2);
}
@Override
public void visitArrayAccessExpression(final PsiArrayAccessExpression slice) {
final PsiArrayAccessExpression slice2 = (PsiArrayAccessExpression)myMatchingVisitor.getElement();
myMatchingVisitor.setResult(myMatchingVisitor.match(slice.getArrayExpression(), slice2.getArrayExpression()) &&
myMatchingVisitor.match(slice.getIndexExpression(), slice2.getIndexExpression()));
}
@Override
public void visitMethodReferenceExpression(PsiMethodReferenceExpression expression) {
final PsiElement element = myMatchingVisitor.getElement();
if (!(element instanceof PsiMethodReferenceExpression)) {
myMatchingVisitor.setResult(false);
return;
}
super.visitMethodReferenceExpression(expression);
}
@Override
public void visitReferenceExpression(final PsiReferenceExpression reference) {
final PsiExpression qualifier = reference.getQualifierExpression();
final PsiElement nameElement = reference.getReferenceNameElement();
final MatchContext context = myMatchingVisitor.getMatchContext();
MatchingHandler _handler = nameElement != null ? context.getPattern().getHandlerSimple(nameElement) : null;
if (!(_handler instanceof SubstitutionHandler)) _handler = context.getPattern().getHandlerSimple(reference);
final PsiElement element = myMatchingVisitor.getElement();
PsiElement other = element instanceof PsiExpression && context.getOptions().isLooseMatching() ?
PsiUtil.skipParenthesizedExprDown((PsiExpression)element) :
element;
if (_handler instanceof SubstitutionHandler &&
!(context.getPattern().getHandlerSimple(qualifier) instanceof SubstitutionHandler) &&
!(qualifier instanceof PsiThisExpression)
) {
if (other instanceof PsiReferenceExpression) {
final PsiReferenceExpression psiReferenceExpression = (PsiReferenceExpression)other;
final PsiExpression qualifier2 = psiReferenceExpression.getQualifierExpression();
if (qualifier2 == null || (context.getOptions().isLooseMatching() && qualifier2 instanceof PsiThisExpression)) {
other = psiReferenceExpression.getReferenceNameElement();
}
}
final SubstitutionHandler handler = (SubstitutionHandler)_handler;
if (handler.isSubtype() || handler.isStrictSubtype()) {
myMatchingVisitor.setResult(checkMatchWithingHierarchy(other, handler, reference));
}
else {
myMatchingVisitor.setResult(handler.handle(other, context));
}
return;
}
if (!(other instanceof PsiReferenceExpression)) {
myMatchingVisitor.setResult(false);
return;
}
final PsiReferenceExpression reference2 = (PsiReferenceExpression)other;
// just variable
final PsiExpression reference2Qualifier = reference2.getQualifierExpression();
if (qualifier == null && reference2Qualifier == null) {
myMatchingVisitor.setResult(reference.getReferenceNameElement().textMatches(reference2.getReferenceNameElement()));
return;
}
// handle field selection
if (!(other.getParent() instanceof PsiMethodCallExpression) && qualifier != null) {
final PsiElement referenceElement = reference.getReferenceNameElement();
final PsiElement referenceElement2 = reference2.getReferenceNameElement();
if (context.getPattern().isTypedVar(referenceElement)) {
myMatchingVisitor.setResult(myMatchingVisitor.handleTypedElement(referenceElement, referenceElement2));
}
else {
myMatchingVisitor.setResult(
(referenceElement2 != null && referenceElement != null && referenceElement.textMatches(referenceElement2)) ||
referenceElement == referenceElement2);
}
if (!myMatchingVisitor.getResult()) {
return;
}
if (reference2Qualifier != null) {
myMatchingVisitor.setResult(myMatchingVisitor.match(qualifier, reference2Qualifier));
}
else {
final PsiElement referencedElement = MatchUtils.getReferencedElement(other);
if (referencedElement instanceof PsiField) {
final PsiField field = (PsiField)referencedElement;
if (qualifier instanceof PsiThisExpression) {
myMatchingVisitor.setResult(!field.hasModifierProperty(PsiModifier.STATIC));
return;
}
}
final MatchingHandler handler = context.getPattern().getHandler(qualifier);
matchImplicitQualifier(handler, referencedElement, context);
}
return;
}
myMatchingVisitor.setResult(false);
}
private static int countCStyleArrayDeclarationDims(final PsiElement type2) {
if (type2 != null) {
final PsiElement parentElement = type2.getParent();
if (parentElement instanceof PsiVariable) {
final PsiIdentifier psiIdentifier = ((PsiVariable)parentElement).getNameIdentifier();
if (psiIdentifier == null) return 0;
int count = 0;
for (PsiElement sibling = psiIdentifier.getNextSibling(); sibling != null; sibling = sibling.getNextSibling()) {
if (sibling instanceof PsiJavaToken) {
final IElementType tokenType = ((PsiJavaToken)sibling).getTokenType();
if (tokenType == JavaTokenType.LBRACKET) ++count;
else if (tokenType != JavaTokenType.RBRACKET) break;
}
}
return count;
}
}
return 0;
}
private void copyResults(final MatchResultImpl ourResult) {
if (ourResult.hasSons()) {
for (MatchResult son : ourResult.getAllSons()) {
myMatchingVisitor.getMatchContext().getResult().addSon((MatchResultImpl)son);
}
}
}
private boolean matchType(final PsiElement _type, final PsiElement _type2) {
PsiElement el = _type;
PsiElement el2 = _type2;
PsiType type1 = null;
PsiType type2 = null;
// check for generics
if (_type instanceof PsiTypeElement &&
((PsiTypeElement)_type).getInnermostComponentReferenceElement() != null
) {
el = ((PsiTypeElement)_type).getInnermostComponentReferenceElement();
type1 = ((PsiTypeElement)_type).getType();
}
if (_type2 instanceof PsiTypeElement &&
((PsiTypeElement)_type2).getInnermostComponentReferenceElement() != null
) {
el2 = ((PsiTypeElement)_type2).getInnermostComponentReferenceElement();
type2 = ((PsiTypeElement)_type2).getType();
}
PsiElement[] typeparams = null;
if (el2 instanceof PsiJavaCodeReferenceElement) {
typeparams = ((PsiJavaCodeReferenceElement)el2).getParameterList().getTypeParameterElements();
if (typeparams.length > 0) {
el2 = ((PsiJavaCodeReferenceElement)el2).getReferenceNameElement();
}
}
else if (el2 instanceof PsiTypeParameter) {
el2 = ((PsiTypeParameter)el2).getNameIdentifier();
}
else if (el2 instanceof PsiClass && ((PsiClass)el2).hasTypeParameters()
) {
typeparams = ((PsiClass)el2).getTypeParameters();
el2 = ((PsiClass)el2).getNameIdentifier();
}
else if (el2 instanceof PsiMethod && ((PsiMethod)el2).hasTypeParameters()
) {
typeparams = ((PsiMethod)_type2).getTypeParameters();
el2 = ((PsiMethod)_type2).getNameIdentifier();
}
PsiReferenceParameterList list = null;
if (el instanceof PsiJavaCodeReferenceElement) {
list = ((PsiJavaCodeReferenceElement)el).getParameterList();
}
if (list != null && list.getTypeParameterElements().length > 0) {
boolean result = typeparams != null &&
myMatchingVisitor.matchInAnyOrder(
list.getTypeParameterElements(),
typeparams
);
if (!result) return false;
el = ((PsiJavaCodeReferenceElement)el).getReferenceNameElement();
}
else {
if (_type2 instanceof PsiTypeElement) {
type2 = ((PsiTypeElement)_type2).getType();
if (typeparams == null || typeparams.length == 0) {
final PsiJavaCodeReferenceElement innermostComponentReferenceElement =
((PsiTypeElement)_type2).getInnermostComponentReferenceElement();
if (innermostComponentReferenceElement != null) el2 = innermostComponentReferenceElement;
}
else {
el2 = _type2;
}
}
}
final int array2Dims = (type2 != null ? type2.getArrayDimensions() : 0) + countCStyleArrayDeclarationDims(_type2);
final int arrayDims = (type1 != null ? type1.getArrayDimensions() : 0) + countCStyleArrayDeclarationDims(_type);
if (myMatchingVisitor.getMatchContext().getPattern().isTypedVar(el)) {
final SubstitutionHandler handler = (SubstitutionHandler)myMatchingVisitor.getMatchContext().getPattern().getHandler(el);
RegExpPredicate regExpPredicate = null;
if (arrayDims != 0) {
if (arrayDims != array2Dims) {
return false;
}
}
else if (array2Dims != 0) {
regExpPredicate = MatchingHandler.getSimpleRegExpPredicate(handler);
if (regExpPredicate != null) {
regExpPredicate.setNodeTextGenerator(new RegExpPredicate.NodeTextGenerator() {
public String getText(PsiElement element) {
StringBuilder builder = new StringBuilder(RegExpPredicate.getMeaningfulText(element));
for (int i = 0; i < array2Dims; ++i) builder.append("[]");
return builder.toString();
}
});
}
}
try {
if (handler.isSubtype() || handler.isStrictSubtype()) {
return checkMatchWithingHierarchy(el2, handler, el);
}
else {
return handler.handle(el2, myMatchingVisitor.getMatchContext());
}
}
finally {
if (regExpPredicate != null) regExpPredicate.setNodeTextGenerator(null);
}
}
if (array2Dims != arrayDims) {
return false;
}
if (el instanceof PsiIdentifier) {
final PsiElement parent = el.getParent();
if (parent instanceof PsiJavaCodeReferenceElement) {
el = parent;
}
}
if (el2 instanceof PsiIdentifier) {
final PsiElement parent = el2.getParent();
if (parent instanceof PsiJavaCodeReferenceElement) {
el2 = parent;
}
}
final String text = stripTypeParameters(el.getText());
if (text.indexOf('.') == -1 || !(el2 instanceof PsiJavaReference)) {
return MatchUtils.compareWithNoDifferenceToPackage(text, stripTypeParameters(el2.getText()));
}
else {
PsiElement element2 = ((PsiJavaReference)el2).resolve();
if (element2 != null) {
return text.equals(((PsiClass)element2).getQualifiedName());
}
else {
return MatchUtils.compareWithNoDifferenceToPackage(text, el2.getText());
}
}
}
private static String stripTypeParameters(String string) {
final int index = string.indexOf('<');
if (index == -1) {
return string;
}
return string.substring(0, index);
}
private boolean checkMatchWithingHierarchy(PsiElement el2, SubstitutionHandler handler, PsiElement context) {
boolean includeInterfaces = true;
boolean includeClasses = true;
final PsiElement contextParent = context.getParent();
if (contextParent instanceof PsiReferenceList) {
final PsiElement grandParentContext = contextParent.getParent();
if (grandParentContext instanceof PsiClass) {
final PsiClass psiClass = (PsiClass)grandParentContext;
if (contextParent == psiClass.getExtendsList()) {
includeInterfaces = psiClass.isInterface();
}
else if (contextParent == psiClass.getImplementsList()) {
includeClasses = false;
}
}
}
// is type2 is (strict) subtype of type
final NodeIterator node = new HierarchyNodeIterator(el2, includeClasses, includeInterfaces);
if (handler.isStrictSubtype()) {
node.advance();
}
final boolean notPredicate = handler.getPredicate() instanceof NotPredicate;
while (node.hasNext() && !handler.validate(node.current(), 0, -1, myMatchingVisitor.getMatchContext())) {
if (notPredicate) return false;
node.advance();
}
if (node.hasNext()) {
handler.addResult(el2, 0, -1, myMatchingVisitor.getMatchContext());
return true;
}
else {
return false;
}
}
@Override
public void visitConditionalExpression(final PsiConditionalExpression cond) {
final PsiConditionalExpression cond2 = (PsiConditionalExpression)myMatchingVisitor.getElement();
myMatchingVisitor.setResult(myMatchingVisitor.match(cond.getCondition(), cond2.getCondition()) &&
myMatchingVisitor.matchSons(cond, cond2));
}
@Override
public void visitPolyadicExpression(PsiPolyadicExpression expression) {
PsiPolyadicExpression expr2 = (PsiPolyadicExpression)myMatchingVisitor.getElement();
boolean result = expression.getOperationTokenType().equals(expr2.getOperationTokenType());
if (result) {
PsiExpression[] operands1 = expression.getOperands();
PsiExpression[] operands2 = expr2.getOperands();
if (operands1.length != operands2.length) {
result = false;
}
else {
for (int i = 0; i < operands1.length; i++) {
PsiExpression e1 = operands1[i];
PsiExpression e2 = operands2[i];
if (!myMatchingVisitor.match(e1, e2)) {
result = false;
break;
}
}
}
}
myMatchingVisitor.setResult(result);
}
@Override
public void visitVariable(final PsiVariable var) {
myMatchingVisitor.getMatchContext().pushResult();
final PsiIdentifier nameIdentifier = var.getNameIdentifier();
boolean isTypedVar = myMatchingVisitor.getMatchContext().getPattern().isTypedVar(nameIdentifier);
boolean isTypedInitializer = var.getInitializer() != null &&
myMatchingVisitor.getMatchContext().getPattern().isTypedVar(var.getInitializer()) &&
var.getInitializer() instanceof PsiReferenceExpression;
final PsiVariable var2 = (PsiVariable)myMatchingVisitor.getElement();
try {
myMatchingVisitor.setResult((var.getName().equals(var2.getName()) || isTypedVar) &&
((var.getParent() instanceof PsiClass && ((PsiClass)var.getParent()).isInterface()) ||
myMatchingVisitor.match(var.getModifierList(), var2.getModifierList())));
if (myMatchingVisitor.getResult()) {
final PsiTypeElement typeElement1 = var.getTypeElement();
if (typeElement1 != null) {
PsiTypeElement typeElement2 = var2.getTypeElement();
if (typeElement2 == null) {
typeElement2 = JavaPsiFacade.getElementFactory(var2.getProject()).createTypeElement(var2.getType());
}
myMatchingVisitor.setResult(myMatchingVisitor.match(typeElement1, typeElement2));
}
}
if (myMatchingVisitor.getResult()) {
// Check initializer
final PsiExpression var2Initializer = var2.getInitializer();
myMatchingVisitor.setResult(myMatchingVisitor.match(var.getInitializer(), var2Initializer) ||
(isTypedInitializer &&
var2Initializer == null &&
allowsAbsenceOfMatch(var.getInitializer())
));
}
if (myMatchingVisitor.getResult() && var instanceof PsiParameter && var.getParent() instanceof PsiCatchSection) {
myMatchingVisitor.setResult(myMatchingVisitor.match(
((PsiCatchSection)var.getParent()).getCatchBlock(),
((PsiCatchSection)var2.getParent()).getCatchBlock()
));
}
if (myMatchingVisitor.getResult() && isTypedVar) {
myMatchingVisitor.setResult(myMatchingVisitor.handleTypedElement(nameIdentifier, var2.getNameIdentifier()));
}
}
finally {
saveOrDropResult(nameIdentifier, isTypedVar, var2.getNameIdentifier());
}
}
private void matchArrayDims(final PsiNewExpression new1, final PsiNewExpression new2) {
final PsiExpression[] arrayDims = new1.getArrayDimensions();
final PsiExpression[] arrayDims2 = new2.getArrayDimensions();
if (arrayDims.length == arrayDims2.length && arrayDims.length != 0) {
for (int i = 0; i < arrayDims.length; ++i) {
myMatchingVisitor.setResult(myMatchingVisitor.match(arrayDims[i], arrayDims2[i]));
if (!myMatchingVisitor.getResult()) return;
}
}
else {
myMatchingVisitor.setResult((arrayDims == arrayDims2) && myMatchingVisitor.matchSons(new1.getArgumentList(), new2.getArgumentList()));
}
}
private void saveOrDropResult(final PsiIdentifier methodNameNode, final boolean typedVar, final PsiIdentifier methodNameNode2) {
MatchResultImpl ourResult = myMatchingVisitor.getMatchContext().hasResult() ? myMatchingVisitor.getMatchContext().getResult() : null;
myMatchingVisitor.getMatchContext().popResult();
if (myMatchingVisitor.getResult()) {
if (typedVar) {
final SubstitutionHandler handler =
(SubstitutionHandler)myMatchingVisitor.getMatchContext().getPattern().getHandler(methodNameNode);
if (ourResult != null) ourResult.setScopeMatch(true);
handler.setNestedResult(ourResult);
myMatchingVisitor.setResult(handler.handle(methodNameNode2, myMatchingVisitor.getMatchContext()));
if (handler.getNestedResult() != null) { // some constraint prevent from adding
handler.setNestedResult(null);
copyResults(ourResult);
}
}
else if (ourResult != null) {
copyResults(ourResult);
}
}
}
private void matchImplicitQualifier(MatchingHandler matchingHandler, PsiElement target, MatchContext context) {
if (!(matchingHandler instanceof SubstitutionHandler)) {
myMatchingVisitor.setResult(false);
return;
}
final SubstitutionHandler substitutionHandler = (SubstitutionHandler)matchingHandler;
final MatchPredicate predicate = substitutionHandler.getPredicate();
if (substitutionHandler.getMinOccurs() != 0) {
myMatchingVisitor.setResult(false);
return;
}
if (predicate == null) {
myMatchingVisitor.setResult(true);
return;
}
if (target == null) {
myMatchingVisitor.setResult(false);
return;
}
if (target instanceof PsiModifierListOwner && ((PsiModifierListOwner)target).hasModifierProperty(PsiModifier.STATIC)) {
myMatchingVisitor.setResult(predicate.match(null, PsiTreeUtil.getParentOfType(target, PsiClass.class), context));
} else {
final PsiElementFactory factory = JavaPsiFacade.getElementFactory(target.getProject());
final PsiExpression implicitReference = factory.createExpressionFromText("this", target);
myMatchingVisitor.setResult(predicate.match(null, implicitReference, context));
}
}
@Override
public void visitMethodCallExpression(final PsiMethodCallExpression mcall) {
final PsiElement element = myMatchingVisitor.getElement();
if (!(element instanceof PsiMethodCallExpression)) {
myMatchingVisitor.setResult(false);
return;
}
final PsiMethodCallExpression mcall2 = (PsiMethodCallExpression)element;
final PsiReferenceExpression mcallRef1 = mcall.getMethodExpression();
final PsiReferenceExpression mcallRef2 = mcall2.getMethodExpression();
final String mcallname1 = mcallRef1.getReferenceName();
final String mcallname2 = mcallRef2.getReferenceName();
final boolean isTypedVar = myMatchingVisitor.getMatchContext().getPattern().isTypedVar(mcallRef1.getReferenceNameElement());
if (mcallname1 != null && !mcallname1.equals(mcallname2) && !isTypedVar) {
myMatchingVisitor.setResult(false);
return;
}
final PsiExpression qualifier = mcallRef1.getQualifierExpression();
final PsiExpression elementQualifier = mcallRef2.getQualifierExpression();
if (qualifier != null) {
if (elementQualifier != null) {
myMatchingVisitor.setResult(myMatchingVisitor.match(qualifier, elementQualifier));
if (!myMatchingVisitor.getResult()) return;
}
else {
final PsiMethod method = mcall2.resolveMethod();
if (method != null) {
if (qualifier instanceof PsiThisExpression) {
myMatchingVisitor.setResult(!method.hasModifierProperty(PsiModifier.STATIC));
return;
}
}
final MatchingHandler handler = myMatchingVisitor.getMatchContext().getPattern().getHandler(qualifier);
matchImplicitQualifier(handler, method, myMatchingVisitor.getMatchContext());
if (!myMatchingVisitor.getResult()) {
return;
}
}
}
else if (elementQualifier != null) {
myMatchingVisitor.setResult(false);
return;
}
myMatchingVisitor.setResult(myMatchingVisitor.matchSons(mcall.getArgumentList(), mcall2.getArgumentList()));
if (myMatchingVisitor.getResult() && isTypedVar) {
boolean res = myMatchingVisitor.getResult();
res &= myMatchingVisitor.handleTypedElement(mcallRef1.getReferenceNameElement(), mcallRef2.getReferenceNameElement());
myMatchingVisitor.setResult(res);
}
}
@Override
public void visitExpressionStatement(final PsiExpressionStatement expr) {
final PsiExpressionStatement expr2 = (PsiExpressionStatement)myMatchingVisitor.getElement();
myMatchingVisitor.setResult(myMatchingVisitor.match(expr.getExpression(), expr2.getExpression()));
}
@Override
public void visitLiteralExpression(final PsiLiteralExpression const1) {
final PsiLiteralExpression const2 = (PsiLiteralExpression)myMatchingVisitor.getElement();
MatchingHandler handler = (MatchingHandler)const1.getUserData(CompiledPattern.HANDLER_KEY);
if (handler instanceof SubstitutionHandler) {
int offset = 0;
int length = const2.getTextLength();
final String text = const2.getText();
if (length > 2 && text.charAt(0) == '"' && text.charAt(length - 1) == '"') {
length--;
offset++;
}
myMatchingVisitor.setResult(((SubstitutionHandler)handler).handle(const2, offset, length, myMatchingVisitor.getMatchContext()));
}
else if (handler != null) {
myMatchingVisitor.setResult(handler.match(const1, const2, myMatchingVisitor.getMatchContext()));
}
else {
myMatchingVisitor.setResult(const1.textMatches(const2));
}
}
@Override
public void visitAssignmentExpression(final PsiAssignmentExpression assign) {
final PsiAssignmentExpression assign2 = (PsiAssignmentExpression)myMatchingVisitor.getElement();
myMatchingVisitor.setResult(assign.getOperationTokenType().equals(assign2.getOperationTokenType()) &&
myMatchingVisitor.match(assign.getLExpression(), assign2.getLExpression()) &&
myMatchingVisitor.match(assign.getRExpression(), assign2.getRExpression()));
}
@Override
public void visitIfStatement(final PsiIfStatement if1) {
final PsiIfStatement if2 = (PsiIfStatement)myMatchingVisitor.getElement();
myMatchingVisitor.setResult(myMatchingVisitor.match(if1.getCondition(), if2.getCondition()) &&
compareBody(if1.getThenBranch(), if2.getThenBranch()) &&
compareBody(if1.getElseBranch(), if2.getElseBranch()));
}
@Override
public void visitSwitchStatement(final PsiSwitchStatement switch1) {
final PsiSwitchStatement switch2 = (PsiSwitchStatement)myMatchingVisitor.getElement();
myMatchingVisitor.setResult(myMatchingVisitor.match(switch1.getExpression(), switch2.getExpression()) &&
myMatchingVisitor.matchSons(switch1.getBody(), switch2.getBody()));
}
@Override
public void visitForStatement(final PsiForStatement for1) {
final PsiForStatement for2 = (PsiForStatement)myMatchingVisitor.getElement();
final PsiStatement initialization = for1.getInitialization();
MatchingHandler handler = myMatchingVisitor.getMatchContext().getPattern().getHandler(initialization);
myMatchingVisitor.setResult(handler.match(initialization, for2.getInitialization(), myMatchingVisitor.getMatchContext()) &&
myMatchingVisitor.match(for1.getCondition(), for2.getCondition()) &&
myMatchingVisitor.match(for1.getUpdate(), for2.getUpdate()) &&
compareBody(for1.getBody(), for2.getBody()));
}
@Override
public void visitForeachStatement(PsiForeachStatement for1) {
final PsiForeachStatement for2 = (PsiForeachStatement)myMatchingVisitor.getElement();
myMatchingVisitor.setResult(myMatchingVisitor.match(for1.getIterationParameter(), for2.getIterationParameter()) &&
myMatchingVisitor.match(for1.getIteratedValue(), for2.getIteratedValue()) &&
compareBody(for1.getBody(), for2.getBody()));
}
@Override
public void visitWhileStatement(final PsiWhileStatement while1) {
final PsiWhileStatement while2 = (PsiWhileStatement)myMatchingVisitor.getElement();
myMatchingVisitor.setResult(myMatchingVisitor.match(while1.getCondition(), while2.getCondition()) &&
compareBody(while1.getBody(), while2.getBody()));
}
@Override
public void visitBlockStatement(final PsiBlockStatement block) {
if (myMatchingVisitor.getElement() instanceof PsiCodeBlock &&
!(myMatchingVisitor.getElement().getParent() instanceof PsiBlockStatement)
) {
myMatchingVisitor.setResult(myMatchingVisitor.matchSons(block.getCodeBlock(), myMatchingVisitor.getElement()));
}
else {
final PsiBlockStatement block2 = (PsiBlockStatement)myMatchingVisitor.getElement();
myMatchingVisitor.setResult(myMatchingVisitor.matchSons(block, block2));
}
}
@Override
public void visitDeclarationStatement(final PsiDeclarationStatement dcl) {
final PsiDeclarationStatement declaration = (PsiDeclarationStatement)myMatchingVisitor.getElement();
myMatchingVisitor.setResult(myMatchingVisitor.matchInAnyOrder(dcl.getDeclaredElements(), declaration.getDeclaredElements()));
}
@Override
public void visitDoWhileStatement(final PsiDoWhileStatement while1) {
final PsiDoWhileStatement while2 = (PsiDoWhileStatement)myMatchingVisitor.getElement();
myMatchingVisitor.setResult(myMatchingVisitor.match(while1.getCondition(), while2.getCondition()) &&
compareBody(while1.getBody(), while2.getBody()));
}
@Override
public void visitReturnStatement(final PsiReturnStatement return1) {
final PsiReturnStatement return2 = (PsiReturnStatement)myMatchingVisitor.getElement();
myMatchingVisitor.setResult(myMatchingVisitor.match(return1.getReturnValue(), return2.getReturnValue()));
}
@Override
public void visitPostfixExpression(final PsiPostfixExpression postfix) {
final PsiPostfixExpression postfix2 = (PsiPostfixExpression)myMatchingVisitor.getElement();
myMatchingVisitor.setResult(postfix.getOperationTokenType().equals(postfix2.getOperationTokenType())
&& myMatchingVisitor.match(postfix.getOperand(), postfix2.getOperand()));
}
@Override
public void visitPrefixExpression(final PsiPrefixExpression prefix) {
final PsiPrefixExpression prefix2 = (PsiPrefixExpression)myMatchingVisitor.getElement();
myMatchingVisitor.setResult(prefix.getOperationTokenType().equals(prefix2.getOperationTokenType())
&& myMatchingVisitor.match(prefix.getOperand(), prefix2.getOperand()));
}
@Override
public void visitAssertStatement(final PsiAssertStatement assert1) {
final PsiAssertStatement assert2 = (PsiAssertStatement)myMatchingVisitor.getElement();
myMatchingVisitor.setResult(myMatchingVisitor.match(assert1.getAssertCondition(), assert2.getAssertCondition()) &&
myMatchingVisitor.match(assert1.getAssertDescription(), assert2.getAssertDescription()));
}
@Override
public void visitBreakStatement(final PsiBreakStatement break1) {
final PsiBreakStatement break2 = (PsiBreakStatement)myMatchingVisitor.getElement();
myMatchingVisitor.setResult(myMatchingVisitor.match(break1.getLabelIdentifier(), break2.getLabelIdentifier()));
}
@Override
public void visitContinueStatement(final PsiContinueStatement continue1) {
final PsiContinueStatement continue2 = (PsiContinueStatement)myMatchingVisitor.getElement();
myMatchingVisitor.setResult(myMatchingVisitor.match(continue1.getLabelIdentifier(), continue2.getLabelIdentifier()));
}
@Override
public void visitSuperExpression(final PsiSuperExpression super1) {
myMatchingVisitor.setResult(true);
}
@Override
public void visitThisExpression(final PsiThisExpression this1) {
myMatchingVisitor.setResult(myMatchingVisitor.getElement() instanceof PsiThisExpression);
}
@Override
public void visitSynchronizedStatement(final PsiSynchronizedStatement synchronized1) {
final PsiSynchronizedStatement synchronized2 = (PsiSynchronizedStatement)myMatchingVisitor.getElement();
myMatchingVisitor.setResult(myMatchingVisitor.match(synchronized1.getLockExpression(), synchronized2.getLockExpression()) &&
myMatchingVisitor.matchSons(synchronized1.getBody(), synchronized2.getBody()));
}
@Override
public void visitThrowStatement(final PsiThrowStatement throw1) {
final PsiThrowStatement throw2 = (PsiThrowStatement)myMatchingVisitor.getElement();
myMatchingVisitor.setResult(myMatchingVisitor.match(throw1.getException(), throw2.getException()));
}
@Override
public void visitParenthesizedExpression(PsiParenthesizedExpression expr) {
if (myMatchingVisitor.getElement() instanceof PsiParenthesizedExpression) {
myMatchingVisitor.setResult(myMatchingVisitor.matchSons(expr, myMatchingVisitor.getElement()));
}
else {
myMatchingVisitor.setResult(false);
}
}
@Override
public void visitCatchSection(final PsiCatchSection section) {
final PsiCatchSection section2 = (PsiCatchSection)myMatchingVisitor.getElement();
final PsiParameter parameter = section.getParameter();
if (parameter != null) {
myMatchingVisitor.setResult(myMatchingVisitor.match(parameter, section2.getParameter()));
}
else {
myMatchingVisitor.setResult(myMatchingVisitor.match(section.getCatchBlock(), section2.getCatchBlock()));
}
}
@Override
public void visitTryStatement(final PsiTryStatement try1) {
final PsiTryStatement try2 = (PsiTryStatement)myMatchingVisitor.getElement();
myMatchingVisitor.setResult(myMatchingVisitor.matchSons(try1.getTryBlock(), try2.getTryBlock()));
if (!myMatchingVisitor.getResult()) return;
final PsiResourceList resourceList1 = try1.getResourceList();
final PsiCatchSection[] catches1 = try1.getCatchSections();
final PsiCodeBlock finally1 = try1.getFinallyBlock();
final PsiResourceList resourceList2 = try2.getResourceList();
final PsiCatchSection[] catches2 = try2.getCatchSections();
final PsiCodeBlock finally2 = try2.getFinallyBlock();
final boolean looseMatching = myMatchingVisitor.getMatchContext().getOptions().isLooseMatching();
if (!looseMatching &&
((catches1.length == 0 && catches2.length != 0) ||
(finally1 == null && finally2 != null) ||
(resourceList1 == null && resourceList2 != null))
) {
myMatchingVisitor.setResult(false);
}
else {
if (resourceList1 != null) {
if (resourceList2 == null) {
myMatchingVisitor.setResult(false);
return;
}
final List<PsiResourceVariable> resourceVariables1 = resourceList1.getResourceVariables();
final List<PsiResourceVariable> resourceVariables2 = resourceList2.getResourceVariables();
myMatchingVisitor.setResult(myMatchingVisitor.matchInAnyOrder(
resourceVariables1.toArray(new PsiResourceVariable[resourceVariables1.size()]),
resourceVariables2.toArray(new PsiResourceVariable[resourceVariables2.size()])));
if (!myMatchingVisitor.getResult()) return;
}
final List<PsiCatchSection> unmatchedCatchSections = new ArrayList<PsiCatchSection>();
ContainerUtil.addAll(unmatchedCatchSections, catches2);
for (int i = 0, j; i < catches1.length; ++i) {
MatchingHandler handler = myMatchingVisitor.getMatchContext().getPattern().getHandler(catches1[i]);
final PsiElement pinnedNode = handler.getPinnedNode(null);
if (pinnedNode != null) {
myMatchingVisitor.setResult(handler.match(catches1[i], pinnedNode, myMatchingVisitor.getMatchContext()));
if (!myMatchingVisitor.getResult()) return;
}
else {
for (j = 0; j < unmatchedCatchSections.size(); ++j) {
if (handler.match(catches1[i], unmatchedCatchSections.get(j), myMatchingVisitor.getMatchContext())) {
unmatchedCatchSections.remove(j);
break;
}
}
if (j == catches2.length) {
myMatchingVisitor.setResult(false);
return;
}
}
}
if (finally1 != null) {
myMatchingVisitor.setResult(myMatchingVisitor.matchSons(finally1, finally2));
}
if (myMatchingVisitor.getResult() && unmatchedCatchSections.size() > 0 && !looseMatching) {
try2.putUserData(UNMATCHED_CATCH_SECTION_CONTENT_VAR_KEY, unmatchedCatchSections);
}
}
}
@Override
public void visitSwitchLabelStatement(final PsiSwitchLabelStatement case1) {
final PsiSwitchLabelStatement case2 = (PsiSwitchLabelStatement)myMatchingVisitor.getElement();
myMatchingVisitor.setResult(case1.isDefaultCase() == case2.isDefaultCase() &&
myMatchingVisitor.match(case1.getCaseValue(), case2.getCaseValue()));
}
@Override
public void visitInstanceOfExpression(final PsiInstanceOfExpression instanceOf) {
final PsiInstanceOfExpression instanceOf2 = (PsiInstanceOfExpression)myMatchingVisitor.getElement();
myMatchingVisitor.setResult(myMatchingVisitor.match(instanceOf.getOperand(), instanceOf2.getOperand()) &&
matchType(instanceOf.getCheckType(), instanceOf2.getCheckType()));
}
@Override
public void visitNewExpression(final PsiNewExpression new1) {
if (myMatchingVisitor.getElement() instanceof PsiArrayInitializerExpression &&
myMatchingVisitor.getElement().getParent() instanceof PsiVariable &&
new1.getArrayDimensions().length == 0 &&
new1.getArrayInitializer() != null
) {
myMatchingVisitor.setResult(
myMatchingVisitor.match(new1.getClassReference(), ((PsiVariable)myMatchingVisitor.getElement().getParent()).getTypeElement()));
myMatchingVisitor.matchSons(new1.getArrayInitializer(), myMatchingVisitor.getElement());
return;
}
if (!(myMatchingVisitor.getElement() instanceof PsiNewExpression)) {
myMatchingVisitor.setResult(false);
return;
}
final PsiNewExpression new2 = (PsiNewExpression)myMatchingVisitor.getElement();
if (new1.getClassReference() != null) {
if (new2.getClassReference() != null) {
myMatchingVisitor.setResult(myMatchingVisitor.match(new1.getClassReference(), new2.getClassReference()) &&
myMatchingVisitor.matchSons(new1.getArrayInitializer(), new2.getArrayInitializer()));
if (myMatchingVisitor.getResult()) {
// matching dims
matchArrayDims(new1, new2);
}
return;
}
else {
// match array of primitive by new 'T();
final PsiKeyword newKeyword = PsiTreeUtil.getChildOfType(new2, PsiKeyword.class);
final PsiElement element = PsiTreeUtil.getNextSiblingOfType(newKeyword, PsiWhiteSpace.class);
if (element != null && element.getNextSibling() instanceof PsiKeyword) {
((LexicalNodesFilter)LexicalNodesFilter.getInstance()).setCareKeyWords(true);
myMatchingVisitor.setResult(myMatchingVisitor.match(new1.getClassReference(), element.getNextSibling()) &&
myMatchingVisitor.matchSons(new1.getArrayInitializer(), new2.getArrayInitializer()));
((LexicalNodesFilter)LexicalNodesFilter.getInstance()).setCareKeyWords(false);
if (myMatchingVisitor.getResult()) {
// matching dims
matchArrayDims(new1, new2);
}
return;
}
}
}
if (new1.getClassReference() == new2.getClassReference()) {
// probably anonymous class or array of primitive type
((LexicalNodesFilter)LexicalNodesFilter.getInstance()).setCareKeyWords(true);
myMatchingVisitor.setResult(myMatchingVisitor.matchSons(new1, new2));
((LexicalNodesFilter)LexicalNodesFilter.getInstance()).setCareKeyWords(false);
}
else if (new1.getAnonymousClass() == null &&
new1.getClassReference() != null &&
new2.getAnonymousClass() != null) {
// allow matching anonymous class without pattern
myMatchingVisitor.setResult(myMatchingVisitor.match(new1.getClassReference(), new2.getAnonymousClass().getBaseClassReference()) &&
myMatchingVisitor.matchSons(new1.getArgumentList(), new2.getArgumentList()));
}
else {
myMatchingVisitor.setResult(false);
}
}
@Override
public void visitKeyword(PsiKeyword keyword) {
myMatchingVisitor.setResult(keyword.textMatches(myMatchingVisitor.getElement()));
}
@Override
public void visitTypeCastExpression(final PsiTypeCastExpression cast) {
final PsiTypeCastExpression cast2 = (PsiTypeCastExpression)myMatchingVisitor.getElement();
myMatchingVisitor.setResult(myMatchingVisitor.match(cast.getCastType(), cast2.getCastType()) &&
myMatchingVisitor.match(cast.getOperand(), cast2.getOperand()));
}
@Override
public void visitClassObjectAccessExpression(final PsiClassObjectAccessExpression expr) {
final PsiClassObjectAccessExpression expr2 = (PsiClassObjectAccessExpression)myMatchingVisitor.getElement();
myMatchingVisitor.setResult(myMatchingVisitor.match(expr.getOperand(), expr2.getOperand()));
}
@Override
public void visitReferenceElement(final PsiJavaCodeReferenceElement ref) {
myMatchingVisitor.setResult(matchType(ref, myMatchingVisitor.getElement()));
}
@Override
public void visitTypeElement(final PsiTypeElement typeElement) {
myMatchingVisitor.setResult(matchType(typeElement, myMatchingVisitor.getElement()));
}
@Override
public void visitTypeParameter(PsiTypeParameter psiTypeParameter) {
final PsiTypeParameter parameter = (PsiTypeParameter)myMatchingVisitor.getElement();
final PsiElement[] children = psiTypeParameter.getChildren();
final PsiElement[] children2 = parameter.getChildren();
final MatchingHandler handler = myMatchingVisitor.getMatchContext().getPattern().getHandler(children[0]);
if (handler instanceof SubstitutionHandler) {
myMatchingVisitor.setResult(((SubstitutionHandler)handler).handle(children2[0], myMatchingVisitor.getMatchContext()));
}
else {
myMatchingVisitor.setResult(children[0].textMatches(children2[0]));
}
if (myMatchingVisitor.getResult() && children.length > 2) {
// constraint present
if (children2.length == 2) {
myMatchingVisitor.setResult(false);
return;
}
if (!children[2].getFirstChild().textMatches(children2[2].getFirstChild())) {
// constraint type (extends)
myMatchingVisitor.setResult(false);
return;
}
myMatchingVisitor.setResult(myMatchingVisitor.matchInAnyOrder(children[2].getChildren(), children2[2].getChildren()));
}
}
@Override
public void visitClass(PsiClass clazz) {
if (clazz.hasTypeParameters()) {
myMatchingVisitor
.setResult(
myMatchingVisitor.match(clazz.getTypeParameterList(), ((PsiClass)myMatchingVisitor.getElement()).getTypeParameterList()));
if (!myMatchingVisitor.getResult()) return;
}
PsiClass clazz2;
if (myMatchingVisitor.getElement() instanceof PsiDeclarationStatement &&
myMatchingVisitor.getElement().getFirstChild() instanceof PsiClass
) {
clazz2 = (PsiClass)myMatchingVisitor.getElement().getFirstChild();
}
else {
clazz2 = (PsiClass)myMatchingVisitor.getElement();
}
final boolean isTypedVar = myMatchingVisitor.getMatchContext().getPattern().isTypedVar(clazz.getNameIdentifier());
if (clazz.getModifierList().getTextLength() > 0) {
if (!myMatchingVisitor.match(clazz.getModifierList(), clazz2.getModifierList())) {
myMatchingVisitor.setResult(false);
return;
}
}
myMatchingVisitor.setResult((clazz.getName().equals(clazz2.getName()) || isTypedVar) &&
compareClasses(clazz, clazz2));
if (myMatchingVisitor.getResult() && isTypedVar) {
PsiElement id = clazz2.getNameIdentifier();
if (id == null) id = clazz2;
myMatchingVisitor.setResult(myMatchingVisitor.handleTypedElement(clazz.getNameIdentifier(), id));
}
}
@Override
public void visitTypeParameterList(PsiTypeParameterList psiTypeParameterList) {
myMatchingVisitor.setResult(myMatchingVisitor.matchSequentially(
psiTypeParameterList.getFirstChild(),
myMatchingVisitor.getElement().getFirstChild()
));
}
@Override
public void visitMethod(PsiMethod method) {
final PsiIdentifier methodNameNode = method.getNameIdentifier();
final boolean isTypedVar = myMatchingVisitor.getMatchContext().getPattern().isTypedVar(methodNameNode);
final PsiMethod method2 = (PsiMethod)myMatchingVisitor.getElement();
myMatchingVisitor.getMatchContext().pushResult();
try {
if (method.hasTypeParameters()) {
myMatchingVisitor.setResult(
myMatchingVisitor.match(method.getTypeParameterList(), ((PsiMethod)myMatchingVisitor.getElement()).getTypeParameterList()));
if (!myMatchingVisitor.getResult()) return;
}
if (!checkHierarchy(method2, method)) {
myMatchingVisitor.setResult(false);
return;
}
myMatchingVisitor.setResult((method.getName().equals(method2.getName()) || isTypedVar) &&
myMatchingVisitor.match(method.getModifierList(), method2.getModifierList()) &&
myMatchingVisitor.matchSons(method.getParameterList(), method2.getParameterList()) &&
myMatchingVisitor.match(method.getReturnTypeElement(), method2.getReturnTypeElement()) &&
matchInAnyOrder(method.getThrowsList(), method2.getThrowsList(), myMatchingVisitor) &&
myMatchingVisitor.matchSonsOptionally(method.getBody(), method2.getBody()));
}
finally {
final PsiIdentifier methodNameNode2 = method2.getNameIdentifier();
saveOrDropResult(methodNameNode, isTypedVar, methodNameNode2);
}
}
}