/* * 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.impl; import java.util.Collection; import java.util.List; import org.jetbrains.annotations.NotNull; import consulo.annotations.RequiredReadAction; import consulo.csharp.lang.evaluator.ConstantExpressionEvaluator; import consulo.csharp.lang.psi.CSharpAccessModifier; import consulo.csharp.lang.psi.CSharpAttribute; import consulo.csharp.lang.psi.CSharpAttributeList; import consulo.csharp.lang.psi.impl.partial.CSharpCompositeTypeDeclaration; import consulo.csharp.lang.psi.impl.stub.index.AttributeListIndex; import consulo.dotnet.module.DotNetAssemblyUtil; import consulo.dotnet.psi.DotNetAttributeTargetType; import consulo.dotnet.psi.DotNetExpression; import consulo.dotnet.psi.DotNetInheritUtil; import consulo.dotnet.psi.DotNetModifierListOwner; import consulo.dotnet.psi.DotNetTypeDeclaration; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleUtilCore; import com.intellij.psi.PsiElement; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.SmartList; /** * @author VISTALL * @since 08.03.14 */ public class CSharpVisibilityUtil { @RequiredReadAction public static boolean isVisible(@NotNull DotNetModifierListOwner target, @NotNull PsiElement place) { return isVisible(target, place, CSharpAccessModifier.findModifierOrDefault(target)); } @RequiredReadAction private static boolean isVisible(DotNetModifierListOwner target, PsiElement place, CSharpAccessModifier accessModifier) { switch(accessModifier) { case PUBLIC: case NONE: return true; case PROTECTED_INTERNAL: return isVisible(target, place, CSharpAccessModifier.INTERNAL); case INTERNAL: Module targetModule = ModuleUtilCore.findModuleForPsiElement(target); Module placeModule = ModuleUtilCore.findModuleForPsiElement(place); if(targetModule != null) { if(targetModule.equals(placeModule)) { return true; } if(placeModule == null) { return false; } String placeAssemblyName = DotNetAssemblyUtil.getAssemblyTitle(place); if(placeAssemblyName == null) { return false; } List<String> allowListForInternal = findAllowListForInternal(targetModule); return allowListForInternal.contains(placeAssemblyName); } return false; case PROTECTED: { List<DotNetTypeDeclaration> targetTypes = collectAllTypes(target); List<DotNetTypeDeclaration> placeTypes = collectAllTypes(place); for(DotNetTypeDeclaration placeType : placeTypes) { final DotNetTypeDeclaration type = CSharpCompositeTypeDeclaration.selectCompositeOrSelfType(placeType); for(DotNetTypeDeclaration targetType : targetTypes) { String vmQName = targetType.getVmQName(); assert vmQName != null; if(DotNetInheritUtil.isParentOrSelf(vmQName, type, true)) { return true; } } } break; } case PRIVATE: { List<DotNetTypeDeclaration> targetTypes = collectAllTypes(target); List<DotNetTypeDeclaration> placeTypes = collectAllTypes(place); for(DotNetTypeDeclaration placeType : placeTypes) { for(DotNetTypeDeclaration type : targetTypes) { if(placeType.isEquivalentTo(type)) { return true; } } } break; } } return false; } @RequiredReadAction @NotNull public static List<String> findAllowListForInternal(@NotNull Module targetModule) { Collection<CSharpAttributeList> attributeLists = AttributeListIndex.getInstance().get(DotNetAttributeTargetType.ASSEMBLY, targetModule.getProject(), targetModule.getModuleScope()); List<String> list = new SmartList<String>(); for(CSharpAttributeList attributeList : attributeLists) { for(CSharpAttribute attribute : attributeList.getAttributes()) { DotNetTypeDeclaration dotNetTypeDeclaration = attribute.resolveToType(); if(dotNetTypeDeclaration == null) { continue; } if(DotNetTypes2.System.Runtime.CompilerServices.InternalsVisibleToAttribute.equalsIgnoreCase(dotNetTypeDeclaration.getVmQName())) { Module attributeModule = ModuleUtilCore.findModuleForPsiElement(attribute); if(attributeModule == null || !attributeModule.equals(targetModule)) { continue; } DotNetExpression[] parameterExpressions = attribute.getParameterExpressions(); if(parameterExpressions.length == 0) { continue; } String valueAs = new ConstantExpressionEvaluator(parameterExpressions[0]).getValueAs(String.class); if(valueAs != null) { list.add(valueAs); } } } } return list; } @NotNull private static List<DotNetTypeDeclaration> collectAllTypes(PsiElement place) { List<DotNetTypeDeclaration> typeDeclarations = new SmartList<DotNetTypeDeclaration>(); PsiElement type = place; while((type = PsiTreeUtil.getContextOfType(type, DotNetTypeDeclaration.class)) != null) { typeDeclarations.add((DotNetTypeDeclaration) type); } return typeDeclarations; } }