summaryrefslogtreecommitdiff
path: root/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/JavaMatchingVisitor.java
diff options
context:
space:
mode:
Diffstat (limited to 'java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/JavaMatchingVisitor.java')
-rw-r--r--java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/JavaMatchingVisitor.java1637
1 files changed, 1637 insertions, 0 deletions
diff --git a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/JavaMatchingVisitor.java b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/JavaMatchingVisitor.java
new file mode 100644
index 000000000000..0ea857b16362
--- /dev/null
+++ b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/JavaMatchingVisitor.java
@@ -0,0 +1,1637 @@
+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()));
+ }
+ }
+
+ @Override
+ public void visitDocTagValue(final PsiDocTagValue value) {
+ final PsiDocTagValue value2 = (PsiDocTagValue)myMatchingVisitor.getElement();
+ final boolean isTypedVar = myMatchingVisitor.getMatchContext().getPattern().isTypedVar(value);
+
+ if (isTypedVar) {
+ myMatchingVisitor.setResult(myMatchingVisitor.handleTypedElement(value, value2));
+ }
+ else {
+ myMatchingVisitor.setResult(value.textMatches(value2));
+ }
+ }
+
+ 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);
+ }
+ }
+}