public Repository(Project project) { this.DomainByName = new Dictionary <string, Domain>(); this.UnitBySingularName = new Dictionary <string, Unit>(); this.InterfaceBySingularName = new Dictionary <string, Interface>(); this.ClassBySingularName = new Dictionary <string, Class>(); this.CompositeByName = new Dictionary <string, Composite>(); this.TypeBySingularName = new Dictionary <string, Type>(); this.inflector = new Inflector(new CultureInfo("en")); var projectInfo = new RepositoryProject(project); this.CreateDomains(projectInfo); this.CreateUnits(); this.CreateTypes(projectInfo); this.CreateHierarchy(projectInfo); this.CreateMembers(projectInfo); this.FromReflection(projectInfo); this.LinkImplementations(); this.CreateInheritedProperties(); this.CreateReverseProperties(); var ids = new HashSet <Guid>(); foreach (var composite in this.Composites) { this.CheckId(ids, composite.Id, $"{composite.SingularName}", "id"); // TODO: Add id checks for properties foreach (var property in composite.DefinedProperties) { this.CheckId(ids, property.Id, $"{composite.SingularName}.{property.RoleName}", "id"); this.CheckId(ids, property.AssociationId, $"{composite.SingularName}.{property.RoleName}", "association id"); this.CheckId(ids, property.RoleId, $"{composite.SingularName}.{property.RoleName}", "role id"); } foreach (var method in composite.DefinedMethods) { if (!method.AttributeByName.ContainsKey(AttributeNames.Id)) { this.HasErrors = true; Logger.Error($"{method} has no {AttributeNames.Id} attribute."); } } } }
private void CreateDomains(RepositoryProject repositoryProject) { var parentByChild = new Dictionary <string, string>(); foreach (var syntaxTree in repositoryProject.DocumentBySyntaxTree.Keys) { var root = syntaxTree.GetRoot(); foreach (var structDeclaration in root.DescendantNodes().OfType <StructDeclarationSyntax>()) { var semanticModel = repositoryProject.Compilation.GetSemanticModel(syntaxTree); var structureModel = (ITypeSymbol)semanticModel.GetDeclaredSymbol(structDeclaration); var domainAttribute = structureModel.GetAttributes().FirstOrDefault(v => v.AttributeClass.Name.Equals("DomainAttribute")); if (domainAttribute != null) { var id = Guid.Parse((string)domainAttribute.ConstructorArguments.First().Value); var document = repositoryProject.DocumentBySyntaxTree[syntaxTree]; var fileInfo = new FileInfo(document.FilePath); var directoryInfo = new DirectoryInfo(fileInfo.DirectoryName); var domain = new Domain(id, directoryInfo); this.DomainByName.Add(domain.Name, domain); var extendsAttribute = structureModel.GetAttributes().FirstOrDefault(v => v.AttributeClass.Name.Equals("ExtendsAttribute")); var parent = (string)extendsAttribute.ConstructorArguments.First().Value; if (!string.IsNullOrEmpty(parent)) { parentByChild.Add(domain.Name, parent); } } } } foreach (var child in parentByChild.Keys) { var parent = parentByChild[child]; this.DomainByName[child].Base = this.DomainByName[parent]; } }
private void CreateHierarchy(RepositoryProject repositoryProject) { var definedTypeBySingularName = repositoryProject.Assembly.DefinedTypes.Where(v => RepositoryNamespaceName.Equals(v.Namespace)).ToDictionary(v => v.Name); foreach (var composite in this.CompositeByName.Values) { var definedType = definedTypeBySingularName[composite.SingularName]; var allInterfaces = definedType.GetInterfaces(); var directInterfaces = allInterfaces.Except(allInterfaces.SelectMany(t => t.GetInterfaces())); foreach (var definedImplementedInterface in directInterfaces) { if (this.InterfaceBySingularName.TryGetValue(definedImplementedInterface.Name, out var implementedInterface)) { composite.ImplementedInterfaces.Add(implementedInterface); } else { throw new Exception("Can not find implemented interface " + definedImplementedInterface.Name + " on " + composite.SingularName); } } } }
private void FromReflection(RepositoryProject repositoryProject) { var declaredTypeBySingularName = repositoryProject.Assembly.DefinedTypes.Where(v => RepositoryNamespaceName.Equals(v.Namespace)).ToDictionary(v => v.Name); foreach (var composite in this.CompositeByName.Values) { var reflectedType = declaredTypeBySingularName[composite.SingularName]; // Type attributes { var typeAttributesByTypeName = reflectedType.GetCustomAttributes(false).Cast <Attribute>().GroupBy(v => v.GetType()); foreach (var group in typeAttributesByTypeName) { var type = group.Key; var typeName = type.Name; if (typeName.ToLowerInvariant().EndsWith("attribute")) { typeName = typeName.Substring(0, typeName.Length - "attribute".Length); } var attributeUsage = type.GetCustomAttributes <AttributeUsageAttribute>().FirstOrDefault(); if (attributeUsage != null && attributeUsage.AllowMultiple) { composite.AttributesByName[typeName] = group.ToArray(); } else { composite.AttributeByName[typeName] = group.First(); } } } // Property attributes foreach (var property in composite.Properties) { var reflectedProperty = reflectedType.GetProperty(property.RoleName); if (reflectedProperty == null) { this.HasErrors = true; Logger.Error($"{reflectedType.Name}.{property.RoleName} should be public"); continue; } var propertyAttributesByTypeName = reflectedProperty.GetCustomAttributes(false).Cast <Attribute>().GroupBy(v => v.GetType()); var reflectedPropertyType = reflectedProperty.PropertyType; var typeName = this.GetTypeName(reflectedPropertyType); property.Type = this.TypeBySingularName[typeName]; foreach (var group in propertyAttributesByTypeName) { var attributeType = group.Key; var attributeTypeName = attributeType.Name; if (attributeTypeName.ToLowerInvariant().EndsWith("attribute")) { attributeTypeName = attributeTypeName.Substring( 0, attributeTypeName.Length - "attribute".Length); } var attributeUsage = attributeType.GetCustomAttributes <AttributeUsageAttribute>().FirstOrDefault(); if (attributeUsage != null && attributeUsage.AllowMultiple) { property.AttributesByName.Add(attributeTypeName, group.ToArray()); } else { property.AttributeByName.Add(attributeTypeName, group.First()); } } if (property.AttributeByName.Keys.Contains("Multiplicity")) { if (reflectedPropertyType.Name.EndsWith("[]")) { if (property.IsRoleOne) { this.HasErrors = true; Logger.Error($"{reflectedType.Name}.{property.RoleName} should be many"); } } else { if (property.IsRoleMany) { this.HasErrors = true; Logger.Error($"{reflectedType.Name}.{property.RoleName} should be one"); } } } } foreach (var method in composite.Methods) { var reflectedMethod = reflectedType.GetMethod(method.Name); var methodAttributesByType = reflectedMethod.GetCustomAttributes(false).Cast <Attribute>().GroupBy(v => v.GetType()); foreach (var group in methodAttributesByType) { var attributeType = group.Key; var attributeTypeName = attributeType.Name; if (attributeTypeName.ToLowerInvariant().EndsWith("attribute")) { attributeTypeName = attributeTypeName.Substring(0, attributeTypeName.Length - "attribute".Length); } var attributeUsage = attributeType.GetCustomAttributes <AttributeUsageAttribute>().FirstOrDefault(); if (attributeUsage != null && attributeUsage.AllowMultiple) { method.AttributesByName.Add(attributeTypeName, group.ToArray()); } else { method.AttributeByName.Add(attributeTypeName, group.First()); } } } } }
private void CreateMembers(RepositoryProject repositoryProject) { foreach (var syntaxTree in repositoryProject.DocumentBySyntaxTree.Keys) { var root = syntaxTree.GetRoot(); var semanticModel = repositoryProject.SemanticModelBySyntaxTree[syntaxTree]; var document = repositoryProject.DocumentBySyntaxTree[syntaxTree]; var fileInfo = new FileInfo(document.FilePath); var domain = this.Domains.FirstOrDefault(v => v.DirectoryInfo.Contains(fileInfo)); if (domain != null) { var typeDeclaration = root.DescendantNodes().SingleOrDefault(v => v is InterfaceDeclarationSyntax || v is ClassDeclarationSyntax); if (typeDeclaration != null) { var typeSymbol = semanticModel.GetDeclaredSymbol(typeDeclaration); var typeName = typeSymbol.Name; if (domain.PartialTypeBySingularName.TryGetValue(typeName, out var partialType)) { var composite = this.CompositeByName[typeName]; var propertyDeclarations = typeDeclaration.DescendantNodes().OfType <PropertyDeclarationSyntax>(); foreach (var propertyDeclaration in propertyDeclarations) { var propertySymbol = semanticModel.GetDeclaredSymbol(propertyDeclaration); var propertyRoleName = propertySymbol.Name; var xmlDocString = propertySymbol.GetDocumentationCommentXml(null, true); var xmlDoc = !string.IsNullOrWhiteSpace(xmlDocString) ? new XmlDoc(xmlDocString) : null; var property = new Property(this.inflector, composite, propertyRoleName) { XmlDoc = xmlDoc }; partialType.PropertyByName.Add(propertyRoleName, property); composite.PropertyByRoleName.Add(propertyRoleName, property); } var methodDeclarations = typeDeclaration.DescendantNodes().OfType <MethodDeclarationSyntax>(); foreach (var methodDeclaration in methodDeclarations) { var methodSymbol = semanticModel.GetDeclaredSymbol(methodDeclaration); var methodName = methodSymbol.Name; var xmlDocString = methodSymbol.GetDocumentationCommentXml(null, true); var xmlDoc = !string.IsNullOrWhiteSpace(xmlDocString) ? new XmlDoc(xmlDocString) : null; var method = new Method(composite, methodName) { XmlDoc = xmlDoc }; partialType.MethodByName.Add(methodName, method); composite.MethodByName.Add(methodName, method); } } } } } }
private void CreateTypes(RepositoryProject repositoryProject) { foreach (var syntaxTree in repositoryProject.DocumentBySyntaxTree.Keys) { var root = syntaxTree.GetRoot(); var semanticModel = repositoryProject.SemanticModelBySyntaxTree[syntaxTree]; var document = repositoryProject.DocumentBySyntaxTree[syntaxTree]; var fileInfo = new FileInfo(document.FilePath); var interfaceDeclaration = root.DescendantNodes().OfType <InterfaceDeclarationSyntax>().SingleOrDefault(); if (interfaceDeclaration != null) { var typeModel = (ITypeSymbol)semanticModel.GetDeclaredSymbol(interfaceDeclaration); var idAttribute = typeModel.GetAttributes().FirstOrDefault(v => v.AttributeClass.Name.Equals("IdAttribute")); if (idAttribute != null) { var id = Guid.Parse((string)idAttribute.ConstructorArguments.First().Value); var domain = this.Domains.First(v => v.DirectoryInfo.Contains(fileInfo)); var symbol = semanticModel.GetDeclaredSymbol(interfaceDeclaration); if (RepositoryNamespaceName.Equals(symbol.ContainingNamespace.ToDisplayString())) { var interfaceSingularName = symbol.Name; var partialInterface = new PartialInterface(interfaceSingularName); domain.PartialInterfaceByName.Add(interfaceSingularName, partialInterface); domain.PartialTypeBySingularName.Add(interfaceSingularName, partialInterface); if (!this.InterfaceBySingularName.TryGetValue(interfaceSingularName, out var @interface)) { @interface = new Interface(this.inflector, id, interfaceSingularName); this.InterfaceBySingularName.Add(interfaceSingularName, @interface); this.CompositeByName.Add(interfaceSingularName, @interface); this.TypeBySingularName.Add(interfaceSingularName, @interface); } @interface.PartialByDomainName.Add(domain.Name, partialInterface); var xmlDoc = symbol.GetDocumentationCommentXml(null, true); @interface.XmlDoc = !string.IsNullOrWhiteSpace(xmlDoc) ? new XmlDoc(xmlDoc) : null; } } } var classDeclaration = root.DescendantNodes().OfType <ClassDeclarationSyntax>().SingleOrDefault(); if (classDeclaration != null) { var typeModel = (ITypeSymbol)semanticModel.GetDeclaredSymbol(classDeclaration); var idAttribute = typeModel.GetAttributes().FirstOrDefault(v => v.AttributeClass.Name.Equals("IdAttribute")); if (idAttribute != null) { var id = Guid.Parse((string)idAttribute.ConstructorArguments.First().Value); var domain = this.Domains.First(v => v.DirectoryInfo.Contains(fileInfo)); var symbol = semanticModel.GetDeclaredSymbol(classDeclaration); if (RepositoryNamespaceName.Equals(symbol.ContainingNamespace.ToDisplayString())) { var classSingularName = symbol.Name; var partialClass = new PartialClass(classSingularName); domain.PartialClassBySingularName.Add(classSingularName, partialClass); domain.PartialTypeBySingularName.Add(classSingularName, partialClass); if (!this.ClassBySingularName.TryGetValue(classSingularName, out Class @class)) { @class = new Class(this.inflector, id, classSingularName); this.ClassBySingularName.Add(classSingularName, @class); this.CompositeByName.Add(classSingularName, @class); this.TypeBySingularName.Add(classSingularName, @class); } @class.PartialByDomainName.Add(domain.Name, partialClass); var xmlDoc = symbol.GetDocumentationCommentXml(null, true); @class.XmlDoc = !string.IsNullOrWhiteSpace(xmlDoc) ? new XmlDoc(xmlDoc) : null; } } } } }