Either <CompleterError, bool> IsBindable(IPropertySymbol property, BindableInfo bindableInfo) { if (bindableInfo?.IsBindable ?? false) { if (property.IsSealed) { return(CompleterError.CreatePropertyError(property, Messages.POCO_PropertyIsSealed)); } if (!property.IsVirtual) { return(CompleterError.CreatePropertyError(property, Messages.POCO_PropertyIsNotVirual)); } if (property.IsReadOnly) { return(CompleterError.CreatePropertyError(property, Messages.POCO_PropertyHasNoSetter)); } if (property.GetMethod.DeclaredAccessibility != Microsoft.CodeAnalysis.Accessibility.Public) { return(CompleterError.CreatePropertyError(property, Messages.POCO_PropertyHasNoPublicGetter)); } } return(property.IsVirtual && (bindableInfo?.IsBindable ?? true) && property.DeclaredAccessibility == Microsoft.CodeAnalysis.Accessibility.Public && property.GetMethod.DeclaredAccessibility == Microsoft.CodeAnalysis.Accessibility.Public && property.IsAutoImplemented() || bindableInfo.Return(bi => bi.IsBindable, () => false)); }
CompleterResult GetImplementations() { Func <Func <string, string>, string, Func <CompleterError>, Either <CompleterError, string> > getImplementation = (getImpl, interfaceName, check) => { var interfaceType = model.Compilation.GetTypeByMetadataName(interfaceName); if (type.AllInterfaces.Contains(interfaceType)) { var error = check.With(x => x()); if (error != null) { return(error); } return(string.Empty); } return(getImpl(type.Name).AddTabs(1)); }; const string IDataErrorInfoName = "System.ComponentModel.IDataErrorInfo"; Func <string, string, string> getIDataErrorInfoPropertyImplementation = (implementation, name) => type.Properties().Any(m => (m.Name == IDataErrorInfoName + "." + name) || (m.DeclaredAccessibility == Microsoft.CodeAnalysis.Accessibility.Public && m.Name == name)) ? null : implementation; var iDataErrorInfoType = model.Compilation.GetTypeByMetadataName(IDataErrorInfoName); var dataErrorInfoImplementation = type.AllInterfaces.Contains(iDataErrorInfoType) ? ( getIDataErrorInfoPropertyImplementation(DataErrorInfoErrorImplementation, "Error") + getIDataErrorInfoPropertyImplementation(DataErrorInfoIndexerImplementation, "this[]") ) : null; Func <CompleterError> checkRaisePropertyChangedMethod = () => { Func <CompleterError> error = () => CompleterError.CreateForTypeName(type, Messages.POCO_RaisePropertyChangedMethodNotFound.Format(type.Name)); var raisePropertyChangedMethods = methods.GetValueOrDefault("RaisePropertyChanged", ImmutableArray <IMethodSymbol> .Empty); if (raisePropertyChangedMethods.IsEmpty) { return(error()); } var raisePropertyChangedMethod = raisePropertyChangedMethods.FirstOrDefault(method => { if (method.Parameters.Length != 1) { return(false); } var parameter = method.Parameters.Single(); return(parameter.RefKind == RefKind.None && parameter.Type.SpecialType == SpecialType.System_String); }); if (raisePropertyChangedMethod == null) { return(error()); } return(null); }; return(new[] { getImplementation(INPCImplemetation, "System.ComponentModel.INotifyPropertyChanged", checkRaisePropertyChangedMethod), getImplementation(ParentViewModelImplementation, "DevExpress.Mvvm.ISupportParentViewModel", null), getImplementation(SupportServicesImplementation, "DevExpress.Mvvm.ISupportServices", null), dataErrorInfoImplementation, } .AggregateEither(errors => errors.ToImmutableArray(), values => values.ConcatStringsWithNewLines())); }
IEnumerable <CompleterError> GetClassErrors() { if (type.IsSealed) { yield return(CompleterError.CreateForTypeName(type, Messages.POCO_SealedClass.Format(type.Name))); } var iPOCOViewModeType = model.Compilation.GetTypeByMetadataName("DevExpress.Mvvm.POCO.IPOCOViewModel"); if (type.AllInterfaces.Contains(iPOCOViewModeType)) { yield return(CompleterError.CreateForTypeName(type, Messages.POCO_TypeImplementsIPOCOViewModel.Format(type.Name))); } }
Either <CompleterError, string> GenerateCommand(IMethodSymbol method, CommandInfo commandInfo) { var isAsync = method.ReturnType == taskType; var commandName = commandInfo?.Name ?? (method.Name + "Command"); if (type.GetMembers(commandName).Any()) { return(CompleterError.CreateMethodError(method, Messages.POCO_MemberWithSameCommandNameAlreadyExists)); } var methodName = method.Name; var genericParameter = method.Parameters.SingleOrDefault() .With(x => "<" + x.Type.DisplayString(model, x.Location()) + ">"); if (!method.ReturnsVoid && method.ReturnType != taskType) { if (genericParameter == null) { methodName = $"() => {methodName}()"; } else { methodName = $"x => {methodName}(x)"; } } var commandTypeName = (isAsync ? "AsyncCommand" : "DelegateCommand") + genericParameter; var propertyType = isAsync ? "AsyncCommand" + genericParameter : (genericParameter.With(x => $"DelegateCommand{x}") ?? "ICommand"); var canExecuteMethodName = (commandInfo?.CanExecuteMethodName ?? (GetMethods("Can" + methodName).SingleOrDefault()?.Name ?? "null")); var canExecuteMethod = canExecuteMethodName.With(x => GetMethods(x).SingleOrDefault()); if (commandInfo?.CanExecuteMethodName != null && canExecuteMethod == null) { return(CompleterError.CreateMethodError(method, Messages.POCO_MethodNotFound, commandInfo.CanExecuteMethodName)); } if (canExecuteMethod != null) { if (!Enumerable.SequenceEqual(canExecuteMethod.Parameters.Select(x => x.Type), method.Parameters.Select(x => x.Type)) || !canExecuteMethod.Parameters.All(x => x.RefKind == RefKind.None)) { return(CompleterError.CreateMethodError(canExecuteMethod, Messages.POCO_CanExecuteMethodHasIncorrectParameters)); } } var allowMultipleExecution = (commandInfo?.AllowMultipleExecution ?? false) ? ", allowMultipleExecution: true" : null; var useCommandManager = !(commandInfo?.UseCommandManager ?? true) ? ", useCommandManager: false" : null; return ($@"{commandTypeName} _{commandName}; public {propertyType} {commandName} {{ get {{ return _{commandName} ?? (_{commandName} = new {commandTypeName}({methodName}{canExecuteMethodName.With(x => ", " + x)}{allowMultipleExecution}{useCommandManager})); }} }}"); }
Either <CompleterError, bool> IsCommandMethod(IMethodSymbol method, CommandInfo commandInfo) { if (commandInfo?.IsCommand ?? false) { if (method.Parameters.Length > 1) { return(CompleterError.CreateMethodError(method, Messages.POCO_MethodCannotHaveMoreThanOneParameter)); } if (method.Parameters.Length == 1 && method.Parameters.Single().RefKind != RefKind.None) { return(CompleterError.CreateMethodError(method, Messages.POCO_MethodCannotHaveOutORRefParameters)); } } return((commandInfo?.IsCommand ?? (method.DeclaredAccessibility == Microsoft.CodeAnalysis.Accessibility.Public)) && method.MethodKind == MethodKind.Ordinary && !method.IsStatic && (method.ReturnsVoid || method.ReturnType == taskType || (commandInfo?.IsCommand ?? false)) && (!method.Parameters.Any() || (method.Parameters.Length == 1 && method.Parameters.Single().RefKind == RefKind.None))); }
Either <CompleterError, string> GenerateProperty(IPropertySymbol property, BindableInfo bindableInfo) { Func <Chang, string, Either <CompleterError, MethodCallInfo> > getCallInfo = (chang, attributeMethodName) => { var methodName = attributeMethodName ?? $"On{property.Name}Chang{chang}".If(x => property.IsAutoImplemented()); if (methodName != null && GetMethods(methodName).Length > 1) { return(CompleterError.CreatePropertyError(property, Messages.POCO_MoreThanOnePropertyChangedMethod(chang))); } var method = methodName.With(x => GetMethods(x).SingleOrDefault()); if (method == null && attributeMethodName != null) { return(CompleterError.CreateForPropertyName(property, Messages.POCO_PropertyChangedMethodNotFound(chang).Format(attributeMethodName))); } if (method != null) { if (method.Parameters.Length > 1) { return(CompleterError.CreateMethodError(method, Messages.POCO_PropertyChangedCantHaveMoreThanOneParameter(chang))); } if (!method.ReturnsVoid) { return(CompleterError.CreateMethodError(method, Messages.POCO_PropertyChangedCantHaveReturnType(chang))); } if (method.Parameters.Length == 1 && method.Parameters.Single().Type != property.Type) { return(CompleterError.CreateParameterError(method.Parameters.Single(), Messages.POCO_PropertyChangedMethodArgumentTypeShouldMatchPropertyType(chang))); } } var needParameter = method.Return(x => x.Parameters.Length == 1, () => false); var valueName = needParameter ? (chang == Chang.ed ? "oldValue" : "value") : null; var methodCall = method.With(x => $"{x.Name}({valueName});".AddTabs(2)); return(new MethodCallInfo(methodCall, needParameter)); }; return(from changed in getCallInfo(Chang.ed, bindableInfo?.OnPropertyChangedMethodName) from changing in getCallInfo(Chang.ing, bindableInfo?.OnPropertyChangingMethodName) select GenerateProperty(property, changed, changing)); }