//internal void DecodeSecurityAttribute<T>(Symbol targetSymbol, PhpCompilation compilation, ref DecodeWellKnownAttributeArguments<AttributeSyntax, BaseAttributeData, AttributeLocation> arguments) // where T : WellKnownAttributeData, ISecurityAttributeTarget, new() //{ // Debug.Assert(!this.HasErrors); // bool hasErrors; // DeclarativeSecurityAction action = DecodeSecurityAttributeAction(targetSymbol, compilation, arguments.AttributeSyntaxOpt, out hasErrors, arguments.Diagnostics); // if (!hasErrors) // { // T data = arguments.GetOrCreateData<T>(); // SecurityWellKnownAttributeData securityData = data.GetOrCreateData(); // securityData.SetSecurityAttribute(arguments.Index, action, arguments.AttributesCount); // if (this.IsTargetAttribute(targetSymbol, AttributeDescription.PermissionSetAttribute)) // { // string resolvedPathForFixup = DecodePermissionSetAttribute(compilation, arguments.AttributeSyntaxOpt, arguments.Diagnostics); // if (resolvedPathForFixup != null) // { // securityData.SetPathForPermissionSetAttributeFixup(arguments.Index, resolvedPathForFixup, arguments.AttributesCount); // } // } // } //} //private DeclarativeSecurityAction DecodeSecurityAttributeAction(Symbol targetSymbol, PhpCompilation compilation, AttributeSyntax nodeOpt, out bool hasErrors, DiagnosticBag diagnostics) //{ // Debug.Assert((object)targetSymbol != null); // Debug.Assert(targetSymbol.Kind == SymbolKind.Assembly || targetSymbol.Kind == SymbolKind.NamedType || targetSymbol.Kind == SymbolKind.Method); // Debug.Assert(this.IsSecurityAttribute(compilation)); // var ctorArgs = this.CommonConstructorArguments; // if (!ctorArgs.Any()) // { // // NOTE: Security custom attributes must have a valid SecurityAction as its first argument, we have none here. // // NOTE: Ideally, we should always generate 'CS7048: First argument to a security attribute must be a valid SecurityAction' for this case. // // NOTE: However, native compiler allows applying System.Security.Permissions.HostProtectionAttribute attribute without any argument and uses // // NOTE: SecurityAction.LinkDemand as the default SecurityAction in this case. We maintain compatibility with the native compiler for this case. // // BREAKING CHANGE: Even though the native compiler intends to allow only HostProtectionAttribute to be applied without any arguments, // // it doesn't quite do this correctly // // The implementation issue leads to the native compiler allowing any user defined security attribute with a parameterless constructor and a named property argument as the first // // attribute argument to have the above mentioned behavior, even though the comment clearly mentions that this behavior was intended only for the HostProtectionAttribute. // // We currently allow this case only for the HostProtectionAttribute. In future if need arises, we can exactly match native compiler's behavior. // if (this.IsTargetAttribute(targetSymbol, AttributeDescription.HostProtectionAttribute)) // { // hasErrors = false; // return DeclarativeSecurityAction.LinkDemand; // } // } // else // { // TypedConstant firstArg = ctorArgs.First(); // TypeSymbol firstArgType = (TypeSymbol)firstArg.Type; // if ((object)firstArgType != null && firstArgType.Equals(compilation.GetWellKnownType(WellKnownType.System_Security_Permissions_SecurityAction))) // { // return DecodeSecurityAction(firstArg, targetSymbol, nodeOpt, diagnostics, out hasErrors); // } // } // // CS7048: First argument to a security attribute must be a valid SecurityAction // diagnostics.Add(ErrorCode.ERR_SecurityAttributeMissingAction, nodeOpt != null ? nodeOpt.Name.Location : NoLocation.Singleton); // hasErrors = true; // return DeclarativeSecurityAction.None; //} //private DeclarativeSecurityAction DecodeSecurityAction(TypedConstant typedValue, Symbol targetSymbol, AttributeSyntax nodeOpt, DiagnosticBag diagnostics, out bool hasErrors) //{ // Debug.Assert((object)targetSymbol != null); // Debug.Assert(targetSymbol.Kind == SymbolKind.Assembly || targetSymbol.Kind == SymbolKind.NamedType || targetSymbol.Kind == SymbolKind.Method); // int securityAction = (int)typedValue.Value; // bool isPermissionRequestAction; // switch (securityAction) // { // case (int)DeclarativeSecurityAction.InheritanceDemand: // case (int)DeclarativeSecurityAction.LinkDemand: // if (this.IsTargetAttribute(targetSymbol, AttributeDescription.PrincipalPermissionAttribute)) // { // // CS7052: SecurityAction value '{0}' is invalid for PrincipalPermission attribute // string displayString; // Location syntaxLocation = GetSecurityAttributeActionSyntaxLocation(nodeOpt, typedValue, out displayString); // diagnostics.Add(ErrorCode.ERR_PrincipalPermissionInvalidAction, syntaxLocation, displayString); // hasErrors = true; // return DeclarativeSecurityAction.None; // } // isPermissionRequestAction = false; // break; // case 1: // // Native compiler allows security action value 1 for security attributes on types/methods, even though there is no corresponding field in System.Security.Permissions.SecurityAction enum. // // We will maintain compatibility. // case (int)DeclarativeSecurityAction.Assert: // case (int)DeclarativeSecurityAction.Demand: // case (int)DeclarativeSecurityAction.PermitOnly: // case (int)DeclarativeSecurityAction.Deny: // isPermissionRequestAction = false; // break; // case (int)DeclarativeSecurityAction.RequestMinimum: // case (int)DeclarativeSecurityAction.RequestOptional: // case (int)DeclarativeSecurityAction.RequestRefuse: // isPermissionRequestAction = true; // break; // default: // { // // CS7049: Security attribute '{0}' has an invalid SecurityAction value '{1}' // string displayString; // Location syntaxLocation = GetSecurityAttributeActionSyntaxLocation(nodeOpt, typedValue, out displayString); // diagnostics.Add(ErrorCode.ERR_SecurityAttributeInvalidAction, syntaxLocation, nodeOpt != null ? nodeOpt.GetErrorDisplayName() : "", displayString); // hasErrors = true; // return DeclarativeSecurityAction.None; // } // } // // Validate security action for symbol kind // if (isPermissionRequestAction) // { // if (targetSymbol.Kind == SymbolKind.NamedType || targetSymbol.Kind == SymbolKind.Method) // { // // Types and methods cannot take permission requests. // // CS7051: SecurityAction value '{0}' is invalid for security attributes applied to a type or a method // string displayString; // Location syntaxLocation = GetSecurityAttributeActionSyntaxLocation(nodeOpt, typedValue, out displayString); // diagnostics.Add(ErrorCode.ERR_SecurityAttributeInvalidActionTypeOrMethod, syntaxLocation, displayString); // hasErrors = true; // return DeclarativeSecurityAction.None; // } // } // else // { // if (targetSymbol.Kind == SymbolKind.Assembly) // { // // Assemblies cannot take declarative security. // // CS7050: SecurityAction value '{0}' is invalid for security attributes applied to an assembly // string displayString; // Location syntaxLocation = GetSecurityAttributeActionSyntaxLocation(nodeOpt, typedValue, out displayString); // diagnostics.Add(ErrorCode.ERR_SecurityAttributeInvalidActionAssembly, syntaxLocation, displayString); // hasErrors = true; // return DeclarativeSecurityAction.None; // } // } // hasErrors = false; // return (DeclarativeSecurityAction)securityAction; //} //private static Location GetSecurityAttributeActionSyntaxLocation(AttributeSyntax nodeOpt, TypedConstant typedValue, out string displayString) //{ // if (nodeOpt == null) // { // displayString = ""; // return NoLocation.Singleton; // } // var argList = nodeOpt.ArgumentList; // if (argList == null || argList.Arguments.IsEmpty()) // { // // Optional SecurityAction parameter with default value. // displayString = typedValue.Value.ToString(); // return nodeOpt.Location; // } // AttributeArgumentSyntax argSyntax = argList.Arguments[0]; // displayString = argSyntax.ToString(); // return argSyntax.Location; //} ///// <summary> ///// Decodes PermissionSetAttribute applied in source to determine if it needs any fixup during codegen. ///// </summary> ///// <remarks> ///// PermissionSetAttribute needs fixup when it contains an assignment to the 'File' property as a single named attribute argument. ///// Fixup performed is ported from SecurityAttributes::FixUpPermissionSetAttribute. ///// It involves following steps: ///// 1) Verifying that the specified file name resolves to a valid path. ///// 2) Reading the contents of the file into a byte array. ///// 3) Convert each byte in the file content into two bytes containing hexadecimal characters. ///// 4) Replacing the 'File = fileName' named argument with 'Hex = hexFileContent' argument, where hexFileContent is the converted output from step 3) above. ///// ///// Step 1) is performed in this method, i.e. during binding. ///// Remaining steps are performed during serialization as we want to avoid retaining the entire file contents throughout the binding/codegen pass. ///// See <see cref="Microsoft.CodeAnalysis.CodeGen.PermissionSetAttributeWithFileReference"/> for remaining fixup steps. ///// </remarks> ///// <returns>String containing the resolved file path if PermissionSetAttribute needs fixup during codegen, null otherwise.</returns> //private string DecodePermissionSetAttribute(PhpCompilation compilation, AttributeSyntax nodeOpt, DiagnosticBag diagnostics) //{ // Debug.Assert(!this.HasErrors); // string resolvedFilePath = null; // var namedArgs = this.CommonNamedArguments; // if (namedArgs.Length == 1) // { // var namedArg = namedArgs[0]; // NamedTypeSymbol attrType = this.AttributeClass; // string filePropName = PermissionSetAttributeWithFileReference.FilePropertyName; // string hexPropName = PermissionSetAttributeWithFileReference.HexPropertyName; // if (namedArg.Key == filePropName && // PermissionSetAttributeTypeHasRequiredProperty(attrType, filePropName)) // { // // resolve file prop path // var fileName = (string)namedArg.Value.Value; // var resolver = compilation.Options.XmlReferenceResolver; // resolvedFilePath = (resolver != null) ? resolver.ResolveReference(fileName, baseFilePath: null) : null; // if (resolvedFilePath == null) // { // // CS7053: Unable to resolve file path '{0}' specified for the named argument '{1}' for PermissionSet attribute // Location argSyntaxLocation = nodeOpt != null ? nodeOpt.GetNamedArgumentSyntax(filePropName).Location : NoLocation.Singleton; // diagnostics.Add(ErrorCode.ERR_PermissionSetAttributeInvalidFile, argSyntaxLocation, fileName ?? "<null>", filePropName); // } // else if (!PermissionSetAttributeTypeHasRequiredProperty(attrType, hexPropName)) // { // // PermissionSetAttribute was defined in user source, but doesn't have the required Hex property. // // Native compiler still emits the file content as named assignment to 'Hex' property, but this leads to a runtime exception. // // We instead skip the fixup and emit the file property. // // CONSIDER: We may want to consider taking a breaking change and generating an error here. // return null; // } // } // } // return resolvedFilePath; //} // This method checks if the given PermissionSetAttribute type has a property member with the given propName which is writable, non-generic, public and of string type. private static bool PermissionSetAttributeTypeHasRequiredProperty(NamedTypeSymbol permissionSetType, string propName) { var members = permissionSetType.GetMembers(propName); if (members.Length == 1 && members[0].Kind == SymbolKind.Property) { var property = (PropertySymbol)members[0]; if ((object)property.Type != null && property.Type.SpecialType == SpecialType.System_String && property.DeclaredAccessibility == Accessibility.Public && property.GetMemberArity() == 0 && (object)property.SetMethod != null && property.SetMethod.DeclaredAccessibility == Accessibility.Public) { return(true); } } return(false); }
public static MethodSymbol ResolveMethodImplementation(MethodSymbol method, NamedTypeSymbol type) { while (type != null) { var candidates = type.GetMembers(method.RoutineName).OfType <MethodSymbol>().Where(CanOverride); var resolved = ResolveMethodImplementation(method, candidates); if (resolved != null) { return(resolved); } // type = type.BaseType; } // return(null); }
public static MethodSymbol ResolveMethodImplementation(MethodSymbol method, NamedTypeSymbol type) { for (; type != null; type = type.BaseType) { var members = type.GetMembersByPhpName(method.RoutineName).OfType <MethodSymbol>().Where(CanOverride); if (method.ContainingType.IsInterface) { // check explicit interface override members = members.Concat(type.GetMembers(method.ContainingType.GetFullName() + "." + method.RoutineName).OfType <MethodSymbol>()); } var resolved = ResolveMethodImplementation(method, members); if (resolved != null) { return(resolved); } } // return(null); }
public static MethodSymbol ResolveMethodImplementation(MethodSymbol method, NamedTypeSymbol type) { // ignoring System.Object (we don't override its methods from PHP) bool ignoreSystemObject = method.ContainingType.IsPhpType(); for (; type != null; type = type.BaseType) { if (ignoreSystemObject && type.SpecialType == SpecialType.System_Object) { break; } var resolved = ResolveMethodImplementation(method, type.GetMembers()); if (resolved != null) { return(resolved); } } // return(null); }
public static MethodSymbol ResolveMethodImplementation(MethodSymbol method, NamedTypeSymbol type) { // ignoring System.Object (we don't override its methods from PHP) for (; type != null && type.SpecialType != SpecialType.System_Object; type = type.BaseType) { var members = type.GetMembersByPhpName(method.RoutineName).OfType <MethodSymbol>().Where(CanOverride); if (method.ContainingType.IsInterface) { // check explicit interface override members = members.Concat(type.GetMembers(method.ContainingType.GetFullName() + "." + method.RoutineName).OfType <MethodSymbol>()); } var resolved = ResolveMethodImplementation(method, members); if (resolved != null) { return(resolved); } } // return(null); }
//internal void DecodeSecurityAttribute<T>(Symbol targetSymbol, PhpCompilation compilation, ref DecodeWellKnownAttributeArguments<AttributeSyntax, BaseAttributeData, AttributeLocation> arguments) // where T : WellKnownAttributeData, ISecurityAttributeTarget, new() //{ // Debug.Assert(!this.HasErrors); // bool hasErrors; // DeclarativeSecurityAction action = DecodeSecurityAttributeAction(targetSymbol, compilation, arguments.AttributeSyntaxOpt, out hasErrors, arguments.Diagnostics); // if (!hasErrors) // { // T data = arguments.GetOrCreateData<T>(); // SecurityWellKnownAttributeData securityData = data.GetOrCreateData(); // securityData.SetSecurityAttribute(arguments.Index, action, arguments.AttributesCount); // if (this.IsTargetAttribute(targetSymbol, AttributeDescription.PermissionSetAttribute)) // { // string resolvedPathForFixup = DecodePermissionSetAttribute(compilation, arguments.AttributeSyntaxOpt, arguments.Diagnostics); // if (resolvedPathForFixup != null) // { // securityData.SetPathForPermissionSetAttributeFixup(arguments.Index, resolvedPathForFixup, arguments.AttributesCount); // } // } // } //} //private DeclarativeSecurityAction DecodeSecurityAttributeAction(Symbol targetSymbol, PhpCompilation compilation, AttributeSyntax nodeOpt, out bool hasErrors, DiagnosticBag diagnostics) //{ // Debug.Assert((object)targetSymbol != null); // Debug.Assert(targetSymbol.Kind == SymbolKind.Assembly || targetSymbol.Kind == SymbolKind.NamedType || targetSymbol.Kind == SymbolKind.Method); // Debug.Assert(this.IsSecurityAttribute(compilation)); // var ctorArgs = this.CommonConstructorArguments; // if (!ctorArgs.Any()) // { // // NOTE: Security custom attributes must have a valid SecurityAction as its first argument, we have none here. // // NOTE: Ideally, we should always generate 'CS7048: First argument to a security attribute must be a valid SecurityAction' for this case. // // NOTE: However, native compiler allows applying System.Security.Permissions.HostProtectionAttribute attribute without any argument and uses // // NOTE: SecurityAction.LinkDemand as the default SecurityAction in this case. We maintain compatibility with the native compiler for this case. // // BREAKING CHANGE: Even though the native compiler intends to allow only HostProtectionAttribute to be applied without any arguments, // // it doesn't quite do this correctly // // The implementation issue leads to the native compiler allowing any user defined security attribute with a parameterless constructor and a named property argument as the first // // attribute argument to have the above mentioned behavior, even though the comment clearly mentions that this behavior was intended only for the HostProtectionAttribute. // // We currently allow this case only for the HostProtectionAttribute. In future if need arises, we can exactly match native compiler's behavior. // if (this.IsTargetAttribute(targetSymbol, AttributeDescription.HostProtectionAttribute)) // { // hasErrors = false; // return DeclarativeSecurityAction.LinkDemand; // } // } // else // { // TypedConstant firstArg = ctorArgs.First(); // TypeSymbol firstArgType = (TypeSymbol)firstArg.Type; // if ((object)firstArgType != null && firstArgType.Equals(compilation.GetWellKnownType(WellKnownType.System_Security_Permissions_SecurityAction))) // { // return DecodeSecurityAction(firstArg, targetSymbol, nodeOpt, diagnostics, out hasErrors); // } // } // // CS7048: First argument to a security attribute must be a valid SecurityAction // diagnostics.Add(ErrorCode.ERR_SecurityAttributeMissingAction, nodeOpt != null ? nodeOpt.Name.Location : NoLocation.Singleton); // hasErrors = true; // return DeclarativeSecurityAction.None; //} //private DeclarativeSecurityAction DecodeSecurityAction(TypedConstant typedValue, Symbol targetSymbol, AttributeSyntax nodeOpt, DiagnosticBag diagnostics, out bool hasErrors) //{ // Debug.Assert((object)targetSymbol != null); // Debug.Assert(targetSymbol.Kind == SymbolKind.Assembly || targetSymbol.Kind == SymbolKind.NamedType || targetSymbol.Kind == SymbolKind.Method); // int securityAction = (int)typedValue.Value; // bool isPermissionRequestAction; // switch (securityAction) // { // case (int)DeclarativeSecurityAction.InheritanceDemand: // case (int)DeclarativeSecurityAction.LinkDemand: // if (this.IsTargetAttribute(targetSymbol, AttributeDescription.PrincipalPermissionAttribute)) // { // // CS7052: SecurityAction value '{0}' is invalid for PrincipalPermission attribute // string displayString; // Location syntaxLocation = GetSecurityAttributeActionSyntaxLocation(nodeOpt, typedValue, out displayString); // diagnostics.Add(ErrorCode.ERR_PrincipalPermissionInvalidAction, syntaxLocation, displayString); // hasErrors = true; // return DeclarativeSecurityAction.None; // } // isPermissionRequestAction = false; // break; // case 1: // // Native compiler allows security action value 1 for security attributes on types/methods, even though there is no corresponding field in System.Security.Permissions.SecurityAction enum. // // We will maintain compatibility. // case (int)DeclarativeSecurityAction.Assert: // case (int)DeclarativeSecurityAction.Demand: // case (int)DeclarativeSecurityAction.PermitOnly: // case (int)DeclarativeSecurityAction.Deny: // isPermissionRequestAction = false; // break; // case (int)DeclarativeSecurityAction.RequestMinimum: // case (int)DeclarativeSecurityAction.RequestOptional: // case (int)DeclarativeSecurityAction.RequestRefuse: // isPermissionRequestAction = true; // break; // default: // { // // CS7049: Security attribute '{0}' has an invalid SecurityAction value '{1}' // string displayString; // Location syntaxLocation = GetSecurityAttributeActionSyntaxLocation(nodeOpt, typedValue, out displayString); // diagnostics.Add(ErrorCode.ERR_SecurityAttributeInvalidAction, syntaxLocation, nodeOpt != null ? nodeOpt.GetErrorDisplayName() : "", displayString); // hasErrors = true; // return DeclarativeSecurityAction.None; // } // } // // Validate security action for symbol kind // if (isPermissionRequestAction) // { // if (targetSymbol.Kind == SymbolKind.NamedType || targetSymbol.Kind == SymbolKind.Method) // { // // Types and methods cannot take permission requests. // // CS7051: SecurityAction value '{0}' is invalid for security attributes applied to a type or a method // string displayString; // Location syntaxLocation = GetSecurityAttributeActionSyntaxLocation(nodeOpt, typedValue, out displayString); // diagnostics.Add(ErrorCode.ERR_SecurityAttributeInvalidActionTypeOrMethod, syntaxLocation, displayString); // hasErrors = true; // return DeclarativeSecurityAction.None; // } // } // else // { // if (targetSymbol.Kind == SymbolKind.Assembly) // { // // Assemblies cannot take declarative security. // // CS7050: SecurityAction value '{0}' is invalid for security attributes applied to an assembly // string displayString; // Location syntaxLocation = GetSecurityAttributeActionSyntaxLocation(nodeOpt, typedValue, out displayString); // diagnostics.Add(ErrorCode.ERR_SecurityAttributeInvalidActionAssembly, syntaxLocation, displayString); // hasErrors = true; // return DeclarativeSecurityAction.None; // } // } // hasErrors = false; // return (DeclarativeSecurityAction)securityAction; //} //private static Location GetSecurityAttributeActionSyntaxLocation(AttributeSyntax nodeOpt, TypedConstant typedValue, out string displayString) //{ // if (nodeOpt == null) // { // displayString = ""; // return NoLocation.Singleton; // } // var argList = nodeOpt.ArgumentList; // if (argList == null || argList.Arguments.IsEmpty()) // { // // Optional SecurityAction parameter with default value. // displayString = typedValue.Value.ToString(); // return nodeOpt.Location; // } // AttributeArgumentSyntax argSyntax = argList.Arguments[0]; // displayString = argSyntax.ToString(); // return argSyntax.Location; //} ///// <summary> ///// Decodes PermissionSetAttribute applied in source to determine if it needs any fixup during codegen. ///// </summary> ///// <remarks> ///// PermissionSetAttribute needs fixup when it contains an assignment to the 'File' property as a single named attribute argument. ///// Fixup performed is ported from SecurityAttributes::FixUpPermissionSetAttribute. ///// It involves following steps: ///// 1) Verifying that the specified file name resolves to a valid path. ///// 2) Reading the contents of the file into a byte array. ///// 3) Convert each byte in the file content into two bytes containing hexadecimal characters. ///// 4) Replacing the 'File = fileName' named argument with 'Hex = hexFileContent' argument, where hexFileContent is the converted output from step 3) above. ///// ///// Step 1) is performed in this method, i.e. during binding. ///// Remaining steps are performed during serialization as we want to avoid retaining the entire file contents throughout the binding/codegen pass. ///// See <see cref="Microsoft.CodeAnalysis.CodeGen.PermissionSetAttributeWithFileReference"/> for remaining fixup steps. ///// </remarks> ///// <returns>String containing the resolved file path if PermissionSetAttribute needs fixup during codegen, null otherwise.</returns> //private string DecodePermissionSetAttribute(PhpCompilation compilation, AttributeSyntax nodeOpt, DiagnosticBag diagnostics) //{ // Debug.Assert(!this.HasErrors); // string resolvedFilePath = null; // var namedArgs = this.CommonNamedArguments; // if (namedArgs.Length == 1) // { // var namedArg = namedArgs[0]; // NamedTypeSymbol attrType = this.AttributeClass; // string filePropName = PermissionSetAttributeWithFileReference.FilePropertyName; // string hexPropName = PermissionSetAttributeWithFileReference.HexPropertyName; // if (namedArg.Key == filePropName && // PermissionSetAttributeTypeHasRequiredProperty(attrType, filePropName)) // { // // resolve file prop path // var fileName = (string)namedArg.Value.Value; // var resolver = compilation.Options.XmlReferenceResolver; // resolvedFilePath = (resolver != null) ? resolver.ResolveReference(fileName, baseFilePath: null) : null; // if (resolvedFilePath == null) // { // // CS7053: Unable to resolve file path '{0}' specified for the named argument '{1}' for PermissionSet attribute // Location argSyntaxLocation = nodeOpt != null ? nodeOpt.GetNamedArgumentSyntax(filePropName).Location : NoLocation.Singleton; // diagnostics.Add(ErrorCode.ERR_PermissionSetAttributeInvalidFile, argSyntaxLocation, fileName ?? "<null>", filePropName); // } // else if (!PermissionSetAttributeTypeHasRequiredProperty(attrType, hexPropName)) // { // // PermissionSetAttribute was defined in user source, but doesn't have the required Hex property. // // Native compiler still emits the file content as named assignment to 'Hex' property, but this leads to a runtime exception. // // We instead skip the fixup and emit the file property. // // CONSIDER: We may want to consider taking a breaking change and generating an error here. // return null; // } // } // } // return resolvedFilePath; //} // This method checks if the given PermissionSetAttribute type has a property member with the given propName which is writable, non-generic, public and of string type. private static bool PermissionSetAttributeTypeHasRequiredProperty(NamedTypeSymbol permissionSetType, string propName) { var members = permissionSetType.GetMembers(propName); if (members.Length == 1 && members[0].Kind == SymbolKind.Property) { var property = (PropertySymbol)members[0]; if ((object)property.Type != null && property.Type.SpecialType == SpecialType.System_String && property.DeclaredAccessibility == Accessibility.Public && property.GetMemberArity() == 0 && (object)property.SetMethod != null && property.SetMethod.DeclaredAccessibility == Accessibility.Public) { return true; } } return false; }