/* * Copyright 2013-2017 consulo.io * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package consulo.csharp.lang.psi; import org.jetbrains.annotations.NotNull; import consulo.annotations.RequiredReadAction; import consulo.csharp.lang.psi.impl.CSharpTypeUtil; import consulo.csharp.lang.psi.CSharpTypeDeclaration; import consulo.dotnet.psi.DotNetLikeMethodDeclaration; import consulo.dotnet.psi.DotNetModifier; import consulo.dotnet.psi.DotNetParameterListOwner; import consulo.dotnet.psi.DotNetType; import consulo.dotnet.psi.DotNetVirtualImplementOwner; import consulo.dotnet.resolve.DotNetTypeRef; import com.intellij.openapi.util.Comparing; import com.intellij.psi.PsiElement; import com.intellij.util.BitUtil; /** * @author VISTALL * @since 08.11.14 */ public class CSharpElementCompareUtil { public static final int CHECK_RETURN_TYPE = 1 << 0; public static final int CHECK_VIRTUAL_IMPL_TYPE = 1 << 1; @RequiredReadAction public static boolean isEqual(@NotNull PsiElement element, @NotNull PsiElement element2, @NotNull PsiElement scope) { return isEqual(element, element2, 0, scope); } @RequiredReadAction public static boolean isEqualWithVirtualImpl(@NotNull PsiElement element, @NotNull PsiElement element2, @NotNull PsiElement scope) { return isEqual(element, element2, CHECK_VIRTUAL_IMPL_TYPE, scope); } @RequiredReadAction public static boolean isEqual(@NotNull PsiElement element, @NotNull PsiElement element2, int flags, @NotNull PsiElement scope) { if(element == element2) { return true; } if(element instanceof CSharpPropertyDeclaration && element2 instanceof CSharpPropertyDeclaration) { if(!Comparing.equal(((CSharpPropertyDeclaration) element).getName(), ((CSharpPropertyDeclaration) element2).getName())) { return false; } if(!compareVirtualImpl(element, element2, flags, scope)) { return false; } if(BitUtil.isSet(flags, CHECK_RETURN_TYPE) && !CSharpTypeUtil.isTypeEqual(((CSharpPropertyDeclaration) element).toTypeRef(false), ((CSharpPropertyDeclaration) element2).toTypeRef(false), scope)) { return false; } return true; } if(element instanceof CSharpEventDeclaration && element2 instanceof CSharpEventDeclaration) { if(!Comparing.equal(((CSharpEventDeclaration) element).getName(), ((CSharpEventDeclaration) element2).getName())) { return false; } if(!compareVirtualImpl(element, element2, flags, scope)) { return false; } if(BitUtil.isSet(flags, CHECK_RETURN_TYPE) && !CSharpTypeUtil.isTypeEqual(((CSharpEventDeclaration) element).toTypeRef(false), ((CSharpEventDeclaration) element2).toTypeRef(false), scope)) { return false; } return true; } if(element instanceof CSharpFieldDeclaration && element2 instanceof CSharpFieldDeclaration) { return Comparing.equal(((CSharpFieldDeclaration) element).getName(), ((CSharpFieldDeclaration) element2).getName()); } if(element instanceof CSharpTypeDeclaration && element2 instanceof CSharpTypeDeclaration) { if(((CSharpTypeDeclaration) element).getGenericParametersCount() != ((CSharpTypeDeclaration) element2).getGenericParametersCount()) { return false; } return Comparing.equal(((CSharpTypeDeclaration) element).getName(), ((CSharpTypeDeclaration) element2).getName()); } if(element instanceof CSharpConstructorDeclaration && element2 instanceof CSharpConstructorDeclaration) { if(((CSharpConstructorDeclaration) element).hasModifier(DotNetModifier.STATIC) != ((CSharpConstructorDeclaration) element2).hasModifier(DotNetModifier.STATIC)) { return false; } if(((CSharpConstructorDeclaration) element).isDeConstructor() != ((CSharpConstructorDeclaration) element2).isDeConstructor()) { return false; } return compareParameterList(element, element2, scope); } if(element instanceof CSharpIndexMethodDeclaration && element2 instanceof CSharpIndexMethodDeclaration) { if(!compareVirtualImpl(element, element2, flags, scope)) { return false; } if(!compareReturnTypeRef(element, element2, flags, scope)) { return false; } return compareParameterList(element, element2, scope); } if(element instanceof CSharpConversionMethodDeclaration && element2 instanceof CSharpConversionMethodDeclaration) { if(!CSharpTypeUtil.isTypeEqual(((CSharpConversionMethodDeclaration) element).getConversionTypeRef(), ((CSharpConversionMethodDeclaration) element2).getConversionTypeRef(), scope)) { return false; } if(!CSharpTypeUtil.isTypeEqual(((CSharpConversionMethodDeclaration) element).getReturnTypeRef(), ((CSharpConversionMethodDeclaration) element2).getReturnTypeRef(), scope)) { return false; } return compareParameterList(element, element2, scope); } if(element instanceof CSharpMethodDeclaration && element2 instanceof CSharpMethodDeclaration) { if(((CSharpMethodDeclaration) element).getGenericParametersCount() != ((CSharpMethodDeclaration) element2).getGenericParametersCount()) { return false; } if(!Comparing.equal(((CSharpMethodDeclaration) element).getName(), ((CSharpMethodDeclaration) element2).getName())) { return false; } if(!compareReturnTypeRef(element, element2, flags, scope)) { return false; } if(!compareVirtualImpl(element, element2, flags, scope)) { return false; } return compareParameterList(element, element2, scope); } return false; } @RequiredReadAction private static boolean compareReturnTypeRef(@NotNull PsiElement o1, @NotNull PsiElement o2, int flags, @NotNull PsiElement scope) { if(!BitUtil.isSet(flags, CHECK_RETURN_TYPE)) { return true; } DotNetTypeRef returnTypeRef1 = ((DotNetLikeMethodDeclaration) o1).getReturnTypeRef(); DotNetTypeRef returnTypeRef2 = ((DotNetLikeMethodDeclaration) o2).getReturnTypeRef(); return CSharpTypeUtil.isTypeEqual(returnTypeRef1, returnTypeRef2, scope); } @RequiredReadAction private static boolean compareVirtualImpl(@NotNull PsiElement o1, @NotNull PsiElement o2, int flags, @NotNull PsiElement scope) { if(!BitUtil.isSet(flags, CHECK_VIRTUAL_IMPL_TYPE)) { return true; } DotNetType type1 = ((DotNetVirtualImplementOwner) o1).getTypeForImplement(); DotNetType type2 = ((DotNetVirtualImplementOwner) o2).getTypeForImplement(); if(type1 == null && type2 == null) { return true; } if(type1 == null || type2 == null) { return false; } // we need call getTypeRefForImplement() due light element have ref for original DotNetType but getTypeRefForImplement() ill return another return CSharpTypeUtil.isTypeEqual(((DotNetVirtualImplementOwner) o1).getTypeRefForImplement(), ((DotNetVirtualImplementOwner) o2).getTypeRefForImplement(), scope); } @RequiredReadAction private static boolean compareParameterList(@NotNull PsiElement listOwner, @NotNull PsiElement listOwner2, @NotNull PsiElement scope) { DotNetTypeRef[] parameterTypeRefs = ((DotNetParameterListOwner) listOwner).getParameterTypeRefs(); DotNetTypeRef[] parameterTypeRefs1 = ((DotNetParameterListOwner) listOwner2).getParameterTypeRefs(); if(parameterTypeRefs.length != parameterTypeRefs1.length) { return false; } for(int i = 0; i < parameterTypeRefs.length; i++) { DotNetTypeRef parameterTypeRef = parameterTypeRefs[i]; DotNetTypeRef parameterTypeRef1 = parameterTypeRefs1[i]; if(!CSharpTypeUtil.isTypeEqual(parameterTypeRef, parameterTypeRef1, scope)) { return false; } } return true; } }