diff --git a/plugins/csharp/migrations/20220518134047_Initial.Designer.cs b/plugins/csharp/migrations/20220518134047_Initial.Designer.cs index 0a7707b34..66a8a89a8 100644 --- a/plugins/csharp/migrations/20220518134047_Initial.Designer.cs +++ b/plugins/csharp/migrations/20220518134047_Initial.Designer.cs @@ -539,6 +539,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) { b.Navigation("CsharpEnumMembers"); }); + #pragma warning restore 612, 618 } } diff --git a/plugins/csharp/migrations/20230326005354_CsharpEdge_Migration.Designer.cs b/plugins/csharp/migrations/20230326005354_CsharpEdge_Migration.Designer.cs new file mode 100644 index 000000000..24af907df --- /dev/null +++ b/plugins/csharp/migrations/20230326005354_CsharpEdge_Migration.Designer.cs @@ -0,0 +1,576 @@ +// +using System; +using CSharpParser.model; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace CSharpParser.Migrations +{ + [DbContext(typeof(CsharpDbContext))] + [Migration("20230326005354_CsharpEdge_Migration")] + partial class CsharpEdge_Migration + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "6.0.5") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("CSharpParser.model.CsharpAstNode", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("numeric(20,0)"); + + b.Property("Accessibility") + .HasColumnType("integer"); + + b.Property("AstSymbolType") + .HasColumnType("integer"); + + b.Property("AstType") + .HasColumnType("integer"); + + b.Property("AstValue") + .HasColumnType("text"); + + b.Property("EntityHash") + .HasColumnType("bigint"); + + b.Property("Location_range_end_column") + .HasColumnType("bigint"); + + b.Property("Location_range_end_line") + .HasColumnType("bigint"); + + b.Property("Location_range_start_column") + .HasColumnType("bigint"); + + b.Property("Location_range_start_line") + .HasColumnType("bigint"); + + b.Property("Path") + .HasColumnType("text"); + + b.Property("RawKind") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("CsharpAstNodes"); + }); + + modelBuilder.Entity("CSharpParser.model.CsharpClass", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AstNodeId") + .HasColumnType("numeric(20,0)"); + + b.Property("ClassType") + .HasColumnType("integer"); + + b.Property("CsharpNamespaceId") + .HasColumnType("bigint"); + + b.Property("DocumentationCommentXML") + .HasColumnType("text"); + + b.Property("EntityHash") + .HasColumnType("bigint"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("ParentNodeId") + .HasColumnType("numeric(20,0)"); + + b.Property("QualifiedName") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("AstNodeId"); + + b.HasIndex("CsharpNamespaceId"); + + b.HasIndex("ParentNodeId"); + + b.ToTable("CsharpClasses"); + }); + + modelBuilder.Entity("CSharpParser.model.CsharpEdge", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("numeric(20,0)"); + + b.Property("From") + .HasColumnType("numeric(20,0)"); + + b.Property("To") + .HasColumnType("numeric(20,0)"); + + b.Property("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("CsharpEdges"); + }); + + modelBuilder.Entity("CSharpParser.model.CsharpEnum", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AstNodeId") + .HasColumnType("numeric(20,0)"); + + b.Property("CsharpNamespaceId") + .HasColumnType("bigint"); + + b.Property("DocumentationCommentXML") + .HasColumnType("text"); + + b.Property("EntityHash") + .HasColumnType("bigint"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("ParentNodeId") + .HasColumnType("numeric(20,0)"); + + b.Property("QualifiedName") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("AstNodeId"); + + b.HasIndex("CsharpNamespaceId"); + + b.HasIndex("ParentNodeId"); + + b.ToTable("CsharpEnums"); + }); + + modelBuilder.Entity("CSharpParser.model.CsharpEnumMember", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AstNodeId") + .HasColumnType("numeric(20,0)"); + + b.Property("CsharpEnumId") + .HasColumnType("bigint"); + + b.Property("DocumentationCommentXML") + .HasColumnType("text"); + + b.Property("EntityHash") + .HasColumnType("bigint"); + + b.Property("EqualsValue") + .HasColumnType("integer"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("ParentNodeId") + .HasColumnType("numeric(20,0)"); + + b.Property("QualifiedName") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("AstNodeId"); + + b.HasIndex("CsharpEnumId"); + + b.HasIndex("ParentNodeId"); + + b.ToTable("CsharpEnumMembers"); + }); + + modelBuilder.Entity("CSharpParser.model.CsharpEtcEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AstNodeId") + .HasColumnType("numeric(20,0)"); + + b.Property("DeclaratorNodeId") + .HasColumnType("numeric(20,0)"); + + b.Property("DocumentationCommentXML") + .HasColumnType("text"); + + b.Property("EntityHash") + .HasColumnType("bigint"); + + b.Property("EtcEntityType") + .HasColumnType("integer"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("ParentNodeId") + .HasColumnType("numeric(20,0)"); + + b.Property("QualifiedName") + .HasColumnType("text"); + + b.Property("QualifiedType") + .HasColumnType("text"); + + b.Property("TypeHash") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("AstNodeId"); + + b.HasIndex("ParentNodeId"); + + b.ToTable("CsharpEtcEntitys"); + }); + + modelBuilder.Entity("CSharpParser.model.CsharpMethod", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AstNodeId") + .HasColumnType("numeric(20,0)"); + + b.Property("DocumentationCommentXML") + .HasColumnType("text"); + + b.Property("EntityHash") + .HasColumnType("bigint"); + + b.Property("MethodType") + .HasColumnType("integer"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("ParentNodeId") + .HasColumnType("numeric(20,0)"); + + b.Property("QualifiedName") + .HasColumnType("text"); + + b.Property("QualifiedType") + .HasColumnType("text"); + + b.Property("TypeHash") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("AstNodeId"); + + b.HasIndex("ParentNodeId"); + + b.ToTable("CsharpMethods"); + }); + + modelBuilder.Entity("CSharpParser.model.CsharpNamespace", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AstNodeId") + .HasColumnType("numeric(20,0)"); + + b.Property("DocumentationCommentXML") + .HasColumnType("text"); + + b.Property("EntityHash") + .HasColumnType("bigint"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("ParentNodeId") + .HasColumnType("numeric(20,0)"); + + b.Property("QualifiedName") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("AstNodeId"); + + b.HasIndex("ParentNodeId"); + + b.ToTable("CsharpNamespaces"); + }); + + modelBuilder.Entity("CSharpParser.model.CsharpStruct", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AstNodeId") + .HasColumnType("numeric(20,0)"); + + b.Property("CsharpNamespaceId") + .HasColumnType("bigint"); + + b.Property("DocumentationCommentXML") + .HasColumnType("text"); + + b.Property("EntityHash") + .HasColumnType("bigint"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("ParentNodeId") + .HasColumnType("numeric(20,0)"); + + b.Property("QualifiedName") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("AstNodeId"); + + b.HasIndex("CsharpNamespaceId"); + + b.HasIndex("ParentNodeId"); + + b.ToTable("CsharpStructs"); + }); + + modelBuilder.Entity("CSharpParser.model.CsharpVariable", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AstNodeId") + .HasColumnType("numeric(20,0)"); + + b.Property("DocumentationCommentXML") + .HasColumnType("text"); + + b.Property("EntityHash") + .HasColumnType("bigint"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("ParentNodeId") + .HasColumnType("numeric(20,0)"); + + b.Property("QualifiedName") + .HasColumnType("text"); + + b.Property("QualifiedType") + .HasColumnType("text"); + + b.Property("TypeHash") + .HasColumnType("bigint"); + + b.Property("VariableType") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("AstNodeId"); + + b.HasIndex("ParentNodeId"); + + b.ToTable("CsharpVariables"); + }); + + modelBuilder.Entity("CSharpParser.model.CsharpClass", b => + { + b.HasOne("CSharpParser.model.CsharpAstNode", "AstNode") + .WithMany() + .HasForeignKey("AstNodeId"); + + b.HasOne("CSharpParser.model.CsharpNamespace", "CsharpNamespace") + .WithMany() + .HasForeignKey("CsharpNamespaceId"); + + b.HasOne("CSharpParser.model.CsharpAstNode", "ParentNode") + .WithMany() + .HasForeignKey("ParentNodeId"); + + b.Navigation("AstNode"); + + b.Navigation("CsharpNamespace"); + + b.Navigation("ParentNode"); + }); + + modelBuilder.Entity("CSharpParser.model.CsharpEnum", b => + { + b.HasOne("CSharpParser.model.CsharpAstNode", "AstNode") + .WithMany() + .HasForeignKey("AstNodeId"); + + b.HasOne("CSharpParser.model.CsharpNamespace", "CsharpNamespace") + .WithMany() + .HasForeignKey("CsharpNamespaceId"); + + b.HasOne("CSharpParser.model.CsharpAstNode", "ParentNode") + .WithMany() + .HasForeignKey("ParentNodeId"); + + b.Navigation("AstNode"); + + b.Navigation("CsharpNamespace"); + + b.Navigation("ParentNode"); + }); + + modelBuilder.Entity("CSharpParser.model.CsharpEnumMember", b => + { + b.HasOne("CSharpParser.model.CsharpAstNode", "AstNode") + .WithMany() + .HasForeignKey("AstNodeId"); + + b.HasOne("CSharpParser.model.CsharpEnum", null) + .WithMany("CsharpEnumMembers") + .HasForeignKey("CsharpEnumId"); + + b.HasOne("CSharpParser.model.CsharpAstNode", "ParentNode") + .WithMany() + .HasForeignKey("ParentNodeId"); + + b.Navigation("AstNode"); + + b.Navigation("ParentNode"); + }); + + modelBuilder.Entity("CSharpParser.model.CsharpEtcEntity", b => + { + b.HasOne("CSharpParser.model.CsharpAstNode", "AstNode") + .WithMany() + .HasForeignKey("AstNodeId"); + + b.HasOne("CSharpParser.model.CsharpAstNode", "ParentNode") + .WithMany() + .HasForeignKey("ParentNodeId"); + + b.Navigation("AstNode"); + + b.Navigation("ParentNode"); + }); + + modelBuilder.Entity("CSharpParser.model.CsharpMethod", b => + { + b.HasOne("CSharpParser.model.CsharpAstNode", "AstNode") + .WithMany() + .HasForeignKey("AstNodeId"); + + b.HasOne("CSharpParser.model.CsharpAstNode", "ParentNode") + .WithMany() + .HasForeignKey("ParentNodeId"); + + b.Navigation("AstNode"); + + b.Navigation("ParentNode"); + }); + + modelBuilder.Entity("CSharpParser.model.CsharpNamespace", b => + { + b.HasOne("CSharpParser.model.CsharpAstNode", "AstNode") + .WithMany() + .HasForeignKey("AstNodeId"); + + b.HasOne("CSharpParser.model.CsharpAstNode", "ParentNode") + .WithMany() + .HasForeignKey("ParentNodeId"); + + b.Navigation("AstNode"); + + b.Navigation("ParentNode"); + }); + + modelBuilder.Entity("CSharpParser.model.CsharpStruct", b => + { + b.HasOne("CSharpParser.model.CsharpAstNode", "AstNode") + .WithMany() + .HasForeignKey("AstNodeId"); + + b.HasOne("CSharpParser.model.CsharpNamespace", "CsharpNamespace") + .WithMany() + .HasForeignKey("CsharpNamespaceId"); + + b.HasOne("CSharpParser.model.CsharpAstNode", "ParentNode") + .WithMany() + .HasForeignKey("ParentNodeId"); + + b.Navigation("AstNode"); + + b.Navigation("CsharpNamespace"); + + b.Navigation("ParentNode"); + }); + + modelBuilder.Entity("CSharpParser.model.CsharpVariable", b => + { + b.HasOne("CSharpParser.model.CsharpAstNode", "AstNode") + .WithMany() + .HasForeignKey("AstNodeId"); + + b.HasOne("CSharpParser.model.CsharpAstNode", "ParentNode") + .WithMany() + .HasForeignKey("ParentNodeId"); + + b.Navigation("AstNode"); + + b.Navigation("ParentNode"); + }); + + modelBuilder.Entity("CSharpParser.model.CsharpEnum", b => + { + b.Navigation("CsharpEnumMembers"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/plugins/csharp/migrations/20230326005354_CsharpEdge_Migration.cs b/plugins/csharp/migrations/20230326005354_CsharpEdge_Migration.cs new file mode 100644 index 000000000..99351bd2a --- /dev/null +++ b/plugins/csharp/migrations/20230326005354_CsharpEdge_Migration.cs @@ -0,0 +1,32 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace CSharpParser.Migrations +{ + public partial class CsharpEdge_Migration : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "CsharpEdges", + columns: table => new + { + Id = table.Column(type: "numeric(20,0)", nullable: false), + From = table.Column(type: "numeric(20,0)", nullable: false), + To = table.Column(type: "numeric(20,0)", nullable: false), + Type = table.Column(type: "integer", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_CsharpEdges", x => x.Id); + }); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "CsharpEdges"); + } + } +} diff --git a/plugins/csharp/migrations/CsharpDbContextModelSnapshot.cs b/plugins/csharp/migrations/CsharpDbContextModelSnapshot.cs index 20ebbc516..c44b56ddd 100644 --- a/plugins/csharp/migrations/CsharpDbContextModelSnapshot.cs +++ b/plugins/csharp/migrations/CsharpDbContextModelSnapshot.cs @@ -6,6 +6,8 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +#nullable disable + namespace CSharpParser.Migrations { [DbContext(typeof(CsharpDbContext))] @@ -15,9 +17,10 @@ protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("Relational:MaxIdentifierLength", 63) - .HasAnnotation("ProductVersion", "5.0.10") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + .HasAnnotation("ProductVersion", "6.0.5") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); modelBuilder.Entity("CSharpParser.model.CsharpAstNode", b => { @@ -67,8 +70,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); b.Property("AstNodeId") .HasColumnType("numeric(20,0)"); @@ -105,12 +109,33 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("CsharpClasses"); }); + modelBuilder.Entity("CSharpParser.model.CsharpEdge", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("numeric(20,0)"); + + b.Property("From") + .HasColumnType("numeric(20,0)"); + + b.Property("To") + .HasColumnType("numeric(20,0)"); + + b.Property("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("CsharpEdges"); + }); + modelBuilder.Entity("CSharpParser.model.CsharpEnum", b => { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); b.Property("AstNodeId") .HasColumnType("numeric(20,0)"); @@ -148,8 +173,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); b.Property("AstNodeId") .HasColumnType("numeric(20,0)"); @@ -190,8 +216,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); b.Property("AstNodeId") .HasColumnType("numeric(20,0)"); @@ -236,8 +263,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); b.Property("AstNodeId") .HasColumnType("numeric(20,0)"); @@ -279,8 +307,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); b.Property("AstNodeId") .HasColumnType("numeric(20,0)"); @@ -313,8 +342,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); b.Property("AstNodeId") .HasColumnType("numeric(20,0)"); @@ -352,8 +382,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); b.Property("AstNodeId") .HasColumnType("numeric(20,0)"); diff --git a/plugins/csharp/model/CsharpDbContext.cs b/plugins/csharp/model/CsharpDbContext.cs index eaef779d1..b32032498 100644 --- a/plugins/csharp/model/CsharpDbContext.cs +++ b/plugins/csharp/model/CsharpDbContext.cs @@ -5,7 +5,22 @@ namespace CSharpParser.model { class CsharpDbContext : DbContext { - public CsharpDbContext(DbContextOptions options) : base(options) { } + private readonly bool isMigration = false; + public CsharpDbContext() + { + isMigration = true; + } + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + if (isMigration) + { + optionsBuilder.UseNpgsql(@"Server=localhost;Port=5432;Database=migrations;User Id=compass;Password=compass"); + base.OnConfiguring(optionsBuilder); + } + } + + public CsharpDbContext(DbContextOptions options) : base(options) { } public DbSet CsharpAstNodes { get; set; } public DbSet CsharpNamespaces { get; set; } @@ -16,8 +31,7 @@ public CsharpDbContext(DbContextOptions options) : base(options) { } public DbSet CsharpEnums { get; set; } public DbSet CsharpEnumMembers { get; set; } public DbSet CsharpEtcEntitys { get; set; } - - + public DbSet CsharpEdges { get; set; } } } diff --git a/plugins/csharp/model/CsharpEdge.cs b/plugins/csharp/model/CsharpEdge.cs new file mode 100644 index 000000000..e60a7dd6f --- /dev/null +++ b/plugins/csharp/model/CsharpEdge.cs @@ -0,0 +1,21 @@ +using System; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; + +namespace CSharpParser.model +{ + enum EdgeType + { + PROVIDE, + IMPLEMENT, + USE, + DEPEND + } + class CsharpEdge + { + public ulong Id { get; set; } + public ulong From { get; set; } + public ulong To { get; set; } + public EdgeType Type { get; set; } + } +} \ No newline at end of file diff --git a/plugins/csharp/parser/src/csharpparser.cpp b/plugins/csharp/parser/src/csharpparser.cpp index 44dfee381..ac8ba45fe 100644 --- a/plugins/csharp/parser/src/csharpparser.cpp +++ b/plugins/csharp/parser/src/csharpparser.cpp @@ -83,6 +83,7 @@ bool CsharpParser::parseProjectBuildPath(const std::vector& paths_) std::string line; std::stringstream log_str(log.get()); + LOG(warning) << log_str.str(); int countFull = 0, countPart = 0; while(std::getline(log_str, line, '\n')) diff --git a/plugins/csharp/parser/src_csharp/AstVisitor.cs b/plugins/csharp/parser/src_csharp/AstVisitor.cs index b64fce38e..c59e0553a 100644 --- a/plugins/csharp/parser/src_csharp/AstVisitor.cs +++ b/plugins/csharp/parser/src_csharp/AstVisitor.cs @@ -143,6 +143,17 @@ public override void VisitNamespaceDeclaration(NamespaceDeclarationSyntax node) DbContext.CsharpNamespaces.Add(csharpNamespace); } + CsharpEtcEntity expr = new CsharpEtcEntity + { + AstNode = astNode, + DocumentationCommentXML = Model.GetDeclaredSymbol(node).GetDocumentationCommentXml(), + EntityHash = astNode.EntityHash, + DeclaratorNodeId = astNode.Id, + Name = node.ToString(), + QualifiedName = qName + }; + DbContext.CsharpEtcEntitys.Add(expr); + base.VisitNamespaceDeclaration(node); } @@ -178,7 +189,18 @@ public override void VisitInterfaceDeclaration(InterfaceDeclarationSyntax node) QualifiedName = qName, DocumentationCommentXML = Model.GetDeclaredSymbol(node).GetDocumentationCommentXml(), EntityHash = astNode.EntityHash - }; + }; + + CsharpEtcEntity expr = new CsharpEtcEntity + { + AstNode = astNode, + DocumentationCommentXML = Model.GetDeclaredSymbol(node).GetDocumentationCommentXml(), + EntityHash = astNode.EntityHash, + DeclaratorNodeId = astNode.Id, + Name = node.ToString(), + QualifiedName = qName + }; + DbContext.CsharpEtcEntitys.Add(expr); foreach (PropertyDeclarationSyntax propertyDeclaration in node.Members.OfType()) { @@ -231,6 +253,17 @@ public override void VisitStructDeclaration(StructDeclarationSyntax node) EntityHash = astNode.EntityHash }; + CsharpEtcEntity expr = new CsharpEtcEntity + { + AstNode = astNode, + DocumentationCommentXML = Model.GetDeclaredSymbol(node).GetDocumentationCommentXml(), + EntityHash = astNode.EntityHash, + DeclaratorNodeId = astNode.Id, + Name = node.ToString(), + QualifiedName = qName + }; + DbContext.CsharpEtcEntitys.Add(expr); + foreach (VariableDeclarationSyntax variableDeclaration in node.Members.OfType()) { //WriteLine($"Variable name: {variableDeclaration.Variables.First().Identifier}"); @@ -329,6 +362,17 @@ public override void VisitClassDeclaration(ClassDeclarationSyntax node) EntityHash = astNode.EntityHash }; + CsharpEtcEntity expr = new CsharpEtcEntity + { + AstNode = astNode, + DocumentationCommentXML = Model.GetDeclaredSymbol(node).GetDocumentationCommentXml(), + EntityHash = astNode.EntityHash, + DeclaratorNodeId = astNode.Id, + Name = node.ToString(), + QualifiedName = qName + }; + DbContext.CsharpEtcEntitys.Add(expr); + foreach (var variableDeclaration in node.Members.OfType()) { //WriteLine($"Variable name: {variableDeclaration.Variables.First().Identifier}"); @@ -427,6 +471,17 @@ public override void VisitRecordDeclaration(RecordDeclarationSyntax node) { EntityHash = astNode.EntityHash }; + CsharpEtcEntity expr = new CsharpEtcEntity + { + AstNode = astNode, + DocumentationCommentXML = Model.GetDeclaredSymbol(node).GetDocumentationCommentXml(), + EntityHash = astNode.EntityHash, + DeclaratorNodeId = astNode.Id, + Name = node.ToString(), + QualifiedName = qName + }; + DbContext.CsharpEtcEntitys.Add(expr); + foreach (var variableDeclaration in node.Members.OfType()) { //WriteLine($"Variable name: {variableDeclaration.Variables.First().Identifier}"); @@ -518,6 +573,18 @@ private void VisitDelegateDecl(DelegateDeclarationSyntax node, CsharpAstNode par MethodType = MethodTypeEnum.Delegate }; + CsharpEtcEntity expr = new CsharpEtcEntity + { + AstNode = astNode, + DocumentationCommentXML = Model.GetDeclaredSymbol(node).GetDocumentationCommentXml(), + EntityHash = astNode.EntityHash, + ParentNode = parent, + DeclaratorNodeId = astNode.Id, + Name = node.ToString(), + QualifiedName = qName + }; + DbContext.CsharpEtcEntitys.Add(expr); + if (node.ParameterList.Parameters.Count > 0) { VisitMethodParameters(node.ParameterList.Parameters, astNode); @@ -552,6 +619,18 @@ private void VisitDestructorDecl(DestructorDeclarationSyntax node, CsharpAstNode MethodType = MethodTypeEnum.Destuctor }; + CsharpEtcEntity expr = new CsharpEtcEntity + { + AstNode = astNode, + DocumentationCommentXML = Model.GetDeclaredSymbol(node).GetDocumentationCommentXml(), + EntityHash = astNode.EntityHash, + ParentNode = parent, + DeclaratorNodeId = astNode.Id, + Name = node.ToString(), + QualifiedName = qName + }; + DbContext.CsharpEtcEntitys.Add(expr); + if (node.ParameterList.Parameters.Count > 0) { VisitMethodParameters(node.ParameterList.Parameters,astNode); @@ -591,6 +670,18 @@ private void VisitConstructorDecl(ConstructorDeclarationSyntax node, CsharpAstNo MethodType = MethodTypeEnum.Constructor }; + CsharpEtcEntity expr = new CsharpEtcEntity + { + AstNode = astNode, + DocumentationCommentXML = Model.GetDeclaredSymbol(node).GetDocumentationCommentXml(), + EntityHash = astNode.EntityHash, + ParentNode = parent, + DeclaratorNodeId = astNode.Id, + Name = node.ToString(), + QualifiedName = qName + }; + DbContext.CsharpEtcEntitys.Add(expr); + if (node.ParameterList.Parameters.Count > 0) { VisitMethodParameters(node.ParameterList.Parameters,astNode); @@ -643,6 +734,19 @@ private void VisitMethodDecl(MethodDeclarationSyntax node, CsharpAstNode parent) MethodType = MethodTypeEnum.Method }; + CsharpEtcEntity expr = new CsharpEtcEntity + { + AstNode = astNode, + DocumentationCommentXML = Model.GetDeclaredSymbol(node).GetDocumentationCommentXml(), + EntityHash = astNode.EntityHash, + ParentNode = parent, + DeclaratorNodeId = astNode.Id, + Name = node.ToString(), + QualifiedType = qType, + QualifiedName = qName + }; + DbContext.CsharpEtcEntitys.Add(expr); + if (node.ParameterList.Parameters.Count > 0) { VisitMethodParameters(node.ParameterList.Parameters,astNode); @@ -696,6 +800,19 @@ private void VisitOperatorDecl(OperatorDeclarationSyntax node, CsharpAstNode par MethodType = MethodTypeEnum.Operator }; + CsharpEtcEntity expr = new CsharpEtcEntity + { + AstNode = astNode, + DocumentationCommentXML = Model.GetDeclaredSymbol(node).GetDocumentationCommentXml(), + EntityHash = astNode.EntityHash, + ParentNode = parent, + DeclaratorNodeId = astNode.Id, + Name = Name, + QualifiedType = qType, + QualifiedName = qName + }; + DbContext.CsharpEtcEntitys.Add(expr); + if (node.ParameterList.Parameters.Count > 0) { VisitMethodParameters(node.ParameterList.Parameters,astNode); @@ -814,6 +931,18 @@ private void VisitPropertyDecl(PropertyDeclarationSyntax node, CsharpAstNode par ParentNode = parent }; DbContext.CsharpVariables.Add(variable); + + CsharpEtcEntity expr = new CsharpEtcEntity + { + AstNode = astNode, + DocumentationCommentXML = Model.GetDeclaredSymbol(node).GetDocumentationCommentXml(), + EntityHash = astNode.EntityHash, + ParentNode = parent, + DeclaratorNodeId = astNode.Id, + Name = node.Identifier.Text, + QualifiedType = varQType + }; + DbContext.CsharpEtcEntitys.Add(expr); } private void VisitAccessors(AccessorListSyntax node, String propertyName, CsharpAstNode parent) @@ -903,6 +1032,17 @@ public override void VisitEnumDeclaration(EnumDeclarationSyntax node) EntityHash = astNode.EntityHash }; + CsharpEtcEntity expr = new CsharpEtcEntity + { + AstNode = astNode, + DocumentationCommentXML = Model.GetDeclaredSymbol(node).GetDocumentationCommentXml(), + EntityHash = astNode.EntityHash, + DeclaratorNodeId = astNode.Id, + Name = node.Identifier.Text, + QualifiedName = qName + }; + DbContext.CsharpEtcEntitys.Add(expr); + foreach (EnumMemberDeclarationSyntax enumMemberDeclarationSyntax in node.Members) { csharpEnum.AddMember(VisitEnumMemberDecl(enumMemberDeclarationSyntax, astNode)); @@ -931,6 +1071,19 @@ private CsharpEnumMember VisitEnumMemberDecl(EnumMemberDeclarationSyntax node, C EntityHash = astNode.EntityHash, ParentNode = parent }; + + CsharpEtcEntity expr = new CsharpEtcEntity + { + AstNode = astNode, + DocumentationCommentXML = Model.GetDeclaredSymbol(node).GetDocumentationCommentXml(), + EntityHash = astNode.EntityHash, + ParentNode = parent, + DeclaratorNodeId = astNode.Id, + Name = node.Identifier.Text, + QualifiedName = qName + }; + DbContext.CsharpEtcEntitys.Add(expr); + if (node.EqualsValue != null) { try diff --git a/plugins/csharp/parser/src_csharp/Program.cs b/plugins/csharp/parser/src_csharp/Program.cs index cf86e0854..f5f8755fb 100644 --- a/plugins/csharp/parser/src_csharp/Program.cs +++ b/plugins/csharp/parser/src_csharp/Program.cs @@ -9,12 +9,15 @@ using System.Collections.Generic; using System.Threading.Tasks; using CSharpParser.model; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Storage; +using System.Collections.Concurrent; namespace CSharpParser { class Program { - //private readonly CsharpDbContext _context; + private readonly CsharpDbContext _context; private static string _rootDir = ""; private static string _buildDir = ""; private static string _buildDirBase = ""; @@ -70,7 +73,16 @@ static int Main(string[] args) .Options; CsharpDbContext _context = new CsharpDbContext(options); - _context.Database.Migrate(); + //_context.Database.Migrate(); + try + { + _context.CsharpAstNodes.Count(); + } + catch + { + RelationalDatabaseCreator creator = _context.Database.GetService() as RelationalDatabaseCreator; + creator.CreateTables(); + } IEnumerable allFiles = GetSourceFilesFromDir(_rootDir, ".cs"); IEnumerable assemblies = GetSourceFilesFromDir(_buildDir, ".dll"); @@ -100,7 +112,11 @@ static int Main(string[] args) } var runtask = ParalellRun(csharpConnectionString, threadNum, trees, compilation); + var collecttask = ParalellCollect(csharpConnectionString, threadNum, trees, compilation); + int ret = runtask.Result; + int res = collecttask.Result; + return 0; } @@ -165,6 +181,69 @@ private static async Task ParseTree(CsharpDbContext context, return await ParingTask; } + + private static async Task ParalellCollect(string csharpConnectionString, int threadNum, + List trees, CSharpCompilation compilation) + { + var options = new DbContextOptionsBuilder() + .UseNpgsql(csharpConnectionString) + .Options; + CsharpDbContext dbContext = new CsharpDbContext(options); + + var contextList = new List(); + contextList.Add(dbContext); + for (int i = 1; i < threadNum; i++) + { + CsharpDbContext dbContextInstance = new CsharpDbContext(options); + contextList.Add(dbContextInstance); + } + + var CollectingTasks = new List>(); + ConcurrentDictionary edges = new ConcurrentDictionary(); + int maxThread = threadNum < trees.Count() ? threadNum : trees.Count(); + for (int i = 0; i < maxThread; i++) + { + CollectingTasks.Add(CollectRelation(contextList[i],trees[i],compilation,i,edges)); + } + + int nextTreeIndex = maxThread; + while (CollectingTasks.Count > 0) + { + var finshedTask = await Task.WhenAny(CollectingTasks); + int nextContextIndex = await finshedTask; + + CollectingTasks.Remove(finshedTask); + if (nextTreeIndex < trees.Count) + { + CollectingTasks.Add(CollectRelation(contextList[nextContextIndex], + trees[nextTreeIndex],compilation,nextContextIndex, edges)); + ++nextTreeIndex; + } + } + + foreach (var edge in edges) + { + dbContext.CsharpEdges.Add(edge.Value); + } + + dbContext.SaveChanges(); + + return 0; + } + + private static async Task CollectRelation(CsharpDbContext context, + SyntaxTree tree, CSharpCompilation compilation, int index, ConcurrentDictionary edges) + { + var CollectingTask = Task.Run(() => + { + SemanticModel model = compilation.GetSemanticModel(tree); + var visitor = new RelationCollector(context, model, tree, edges); + visitor.Visit(tree.GetCompilationUnitRoot()); + return index; + }); + return await CollectingTask; + } + public static IEnumerable GetSourceFilesFromDir(string root, string extension) { IEnumerable allFiles = new string[]{}; diff --git a/plugins/csharp/parser/src_csharp/RelationCollector.cs b/plugins/csharp/parser/src_csharp/RelationCollector.cs new file mode 100644 index 000000000..65be1d92d --- /dev/null +++ b/plugins/csharp/parser/src_csharp/RelationCollector.cs @@ -0,0 +1,123 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using static System.Console; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.FindSymbols; +using CSharpParser.model; +using Microsoft.CodeAnalysis; +using System.Threading.Tasks; +using System.Collections.Concurrent; + +namespace CSharpParser +{ + partial class RelationCollector : CSharpSyntaxWalker + { + private readonly CsharpDbContext DbContext; + private readonly SemanticModel Model; + private readonly SyntaxTree Tree; + private readonly ConcurrentDictionary Edges; + + public RelationCollector(CsharpDbContext context, SemanticModel model, SyntaxTree tree, ConcurrentDictionary edges) + { + this.DbContext = context; + this.Model = model; + this.Tree = tree; + this.Edges = edges; + } + + /// + /// Method VisitVariableDeclarator will gather aggregation type of relations. + /// + public override void VisitVariableDeclarator(VariableDeclaratorSyntax node) + { + if (node.Initializer == null) return; + + var symbol = Model.GetSymbolInfo(node.Initializer.Value).Symbol; + if (symbol == null || symbol.ContainingAssembly.Identity != Model.Compilation.Assembly.Identity) return; + + var symbolLocation = symbol.Locations.FirstOrDefault(loc => loc.IsInSource); + if (symbolLocation == null) return; + + var symbolFilePath = symbolLocation.SourceTree?.FilePath; + var usageFilePath = node.SyntaxTree.FilePath; + if (symbolFilePath == null || + usageFilePath == null || + symbolFilePath == usageFilePath) return; + + + // WriteLine($"Value usageFilePath: {usageFilePath}; symbolFilePath: {symbolFilePath}"); + + CsharpEdge csharpEdge = new CsharpEdge(); + csharpEdge.From = fnvHash(usageFilePath); + csharpEdge.To = fnvHash(symbolFilePath); + csharpEdge.Type = EdgeType.USE; + csharpEdge.Id = createIdentifier(csharpEdge); + + Edges.TryAdd(csharpEdge.Id,csharpEdge); + + base.VisitVariableDeclarator(node); + } + + /// + /// Method VisitInvocationExpression will gather association type of relations. + /// + public override void VisitInvocationExpression(InvocationExpressionSyntax node) + { + var methodSymbol = Model.GetSymbolInfo(node).Symbol as IMethodSymbol; + if (methodSymbol == null || + methodSymbol.ContainingAssembly.Identity != Model.Compilation.Assembly.Identity) return; + + var symbolFilePath = methodSymbol.Locations.FirstOrDefault(loc => loc.IsInSource)?.SourceTree?.FilePath; + var usageFilePath = node.SyntaxTree.FilePath; + if (symbolFilePath == null || + usageFilePath == null || + symbolFilePath == usageFilePath) return; + + // WriteLine($"Value usageFilePath: {usageFilePath}; symbolFilePath: {symbolFilePath}"); + + CsharpEdge csharpEdge = new CsharpEdge(); + csharpEdge.From = fnvHash(usageFilePath); + csharpEdge.To = fnvHash(symbolFilePath); + csharpEdge.Type = EdgeType.USE; + csharpEdge.Id = createIdentifier(csharpEdge); + + Edges.TryAdd(csharpEdge.Id,csharpEdge); + + base.VisitInvocationExpression(node); + } + + private ulong createIdentifier(CsharpEdge edge_) + { + return fnvHash($"{edge_.From}{edge_.To}{typeToString(edge_.Type)}"); + } + + private ulong fnvHash(string data_) + { + ulong hash = 14695981039346656037; + + int len = data_.Length; + for (int i = 0; i < len; ++i) + { + hash ^= data_[i]; + hash *= 1099511628211; + } + + return hash; + } + + private string typeToString(EdgeType type_) + { + switch (type_) + { + case EdgeType.PROVIDE: return "Provide"; + case EdgeType.IMPLEMENT: return "Implement"; + case EdgeType.USE: return "Use"; + case EdgeType.DEPEND: return "Depend"; + } + + return string.Empty; + } + } +} \ No newline at end of file diff --git a/plugins/csharp/service/CMakeLists.txt b/plugins/csharp/service/CMakeLists.txt index cfc163255..b3e7763cf 100644 --- a/plugins/csharp/service/CMakeLists.txt +++ b/plugins/csharp/service/CMakeLists.txt @@ -39,6 +39,8 @@ add_subdirectory(src_csharp) add_library(csharpservice SHARED src/csharpservice.cpp + src/csharpdiagram.cpp + src/csharpfilediagram.cpp src/plugin.cpp) target_compile_options(csharpservice PUBLIC -Wno-unknown-pragmas) diff --git a/plugins/csharp/service/csharpservice.thrift b/plugins/csharp/service/csharpservice.thrift index 4d223da5e..9e9708d5e 100644 --- a/plugins/csharp/service/csharpservice.thrift +++ b/plugins/csharp/service/csharpservice.thrift @@ -49,10 +49,10 @@ service CsharpService map getDiagramTypes(1:common.AstNodeId astNodeId) throws (1:common.InvalidId ex) - string getDiagram(1:common.AstNodeId astNodeId, 2:i32 diagramId) - throws (1:common.InvalidId exId, 2:common.Timeout exLong) - list getSyntaxHighlight( 1:common.FileRange range, 2:list content) + + map> getFileUsages(1:common.FileId fileId, 2:bool reverse) + throws (1:common.InvalidId exId, 2:common.Timeout exLong) } \ No newline at end of file diff --git a/plugins/csharp/service/include/service/csharpservice.h b/plugins/csharp/service/include/service/csharpservice.h index 3660098c9..5f31ad6c1 100644 --- a/plugins/csharp/service/include/service/csharpservice.h +++ b/plugins/csharp/service/include/service/csharpservice.h @@ -184,14 +184,6 @@ class CSharpQueryHandler : public CsharpServiceIf _service -> getDiagramTypes(return_, astNodeId_); } - void getDiagram( - std::string& return_, - const core::AstNodeId& astNodeId_, - const std::int32_t diagramId_) override - { - _service -> getDiagram(return_, astNodeId_, diagramId_); - } - void getSyntaxHighlight( std::vector& return_, const core::FileRange& range_, @@ -205,6 +197,14 @@ class CSharpQueryHandler : public CsharpServiceIf _thriftServerPort = port; } + void getFileUsages( + std::map>& return_, + const core::FileId& fileId_, + const bool reverse_) override + { + _service -> getFileUsages(return_, fileId_, reverse_); + } + private: std::unique_ptr _service; static std::stringstream _thriftStream; @@ -219,7 +219,7 @@ using TransportException = apache::thrift::transport::TTransportException; class CsharpServiceHandler : virtual public LanguageServiceIf { - friend class Diagram; + friend class CsharpDiagram; public: CsharpServiceHandler( @@ -321,8 +321,143 @@ class CsharpServiceHandler : virtual public LanguageServiceIf void getSyntaxHighlight( std::vector& return_, const core::FileRange& range_) override; + private: + +enum DiagramType + { + FILE_USAGES, + + FUNCTION_CALL, /*!< In the function call diagram the nodes are functions and + the edges are the function calls between them. The diagram also displays + some dynamic information such as virtual function calls. */ + + DETAILED_CLASS, /*!< This is a classical UML class diagram for the selected + class and its direct children and parents. The nodes contain the methods + and member variables with their visibility. */ + + CLASS_OVERVIEW, /*!< This is a class diagram which contains all classes + which inherit from the current one, and all parents from which the + current one inherits. The methods and member variables are node included + in the nodes, but the type of the member variables are indicated as + aggregation relationship. */ + + CLASS_COLLABORATION, /*!< This returns a class collaboration diagram + which shows the individual class members and their inheritance + hierarchy. */ + + COMPONENT_USERS, /*!< Component users diagram for source file S shows which + source files depend on S through the interfaces S provides. */ + + EXTERNAL_DEPENDENCY, /*!< This diagram shows the module which directory + depends on. The "depends on" diagram on module A traverses the + subdirectories of module A and shows all directories that contain files + that any of the source files in A includes. */ + + EXTERNAL_USERS, /*!< This diagram shows directories (modules) that are + users of the queried module. */ + + INCLUDE_DEPENDENCY, /*!< This diagram shows of the `#include` file + dependencies. */ + + INTERFACE, /*!< Interface diagram shows the used and provided interfaces of + a source code file and shows linking information. */ + + SUBSYSTEM_DEPENDENCY, /*!< This diagram shows the directories relationship + between the subdirectories of the queried module. This diagram is useful + to understand the relationships of the subdirectories (submodules) + of a module. */ + }; + +enum ReferenceType + { + DEFINITION, /*!< By this option the definition(s) of the AST node can be + queried. However according to the "one definition rule" a named entity + can have only one definition, in a parsing several definitions might be + available. This is the case when the project is built for several targets + and in the different builds different definitions are defined for an + entity (e.g. because of an #ifdef section). */ + + DECLARATION, /*!< By this options the declaration(s) of the AST node can be + queried. */ + + USAGE, /*!< By this option the usages of the AST node can be queried, i.e. + the nodes of which the entity hash is identical to the queried one. */ + + THIS_CALLS, /*!< Get function calls in a function. WARNING: If the + definition of the AST node is not unique then it returns the callees of + one of them. */ + + CALLS_OF_THIS, /*!< Get calls of a function. */ + + CALLEE, /*!< Get called functions definitions. WARNING: If the definition of + the AST node is not unique then it returns the callees of one of them. */ + + CALLER, /*!< Get caller functions. */ + + VIRTUAL_CALL, /*!< A function may be used virtually on a base type object. + The exact type of the object is based on dynamic information, which can't + be determined statically. Weak usage returns these possible calls. */ + + FUNC_PTR_CALL, /*!< Functions can be assigned to function pointers which + can be invoked later. This option returns these invocations. */ + + PARAMETER, /*!< This option returns the parameters of a function. */ + + LOCAL_VAR, /*!< This option returns the local variables of a function. */ + + RETURN_TYPE, /*!< This option returns the return type of a function. */ + + OVERRIDE, /*!< This option returns the functions which the given function + overrides. */ + + OVERRIDDEN_BY, /*!< This option returns the overrides of a function. */ + + USAGEREAD, /*!< This option returns the places where a variable is read. */ + + WRITE, /*!< This option returns the places where a variable is written. */ + + READ, + TYPE, /*!< This option returns the type of a variable. */ + + ALIAS, /*!< Types may have aliases, e.g. by typedefs. */ + + INHERIT_FROM, /*!< Types from which the queried type inherits. */ + + INHERIT_BY, /*!< Types by which the queried type is inherited. */ + + DATA_MEMBER, /*!< Data members of a class. */ + + METHOD, /*!< Members of a class. */ + + FRIEND, /*!< The friends of a class. */ + + UNDERLYING_TYPE, /*!< Underlying type of a typedef. */ + + ENUM_CONSTANTS, /*!< Enum constants. */ + + EXPANSION, /*!< Macro expansion. */ + + UNDEFINITION, /*!< Macro undefinition. */ + + EVALUATION, // LINQ evaluation + + DATA_MODIFICATION, // LINQ underlying datadtruct is modified + + CONSTRUCTOR, + + DESTRUCTOR, + + OPERATOR, + + ACCESSOR, + + DELEGATE, + + EVENT + }; + std::shared_ptr _db; util::OdbTransaction _transaction; diff --git a/plugins/csharp/service/src/csharpdiagram.cpp b/plugins/csharp/service/src/csharpdiagram.cpp new file mode 100644 index 000000000..0fa00b8e4 --- /dev/null +++ b/plugins/csharp/service/src/csharpdiagram.cpp @@ -0,0 +1,402 @@ +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include "csharpdiagram.h" + +namespace +{ + +/** + * This function checks if the given container contains a specified value. + * @param v_ A container to inspect. + * @param val_ Value which will be searched. + * @return True if the container contains the value. + */ +template +bool contains(const Cont& c_, const typename Cont::value_type& val_) +{ + return std::find(c_.begin(), c_.end(), val_) != c_.end(); +} + +/** + * This function wraps the content to a HTML tag and adds attributes to it. + */ +std::string graphHtmlTag( + const std::string& tag_, + const std::string& content_, + const std::string& attr_ = "") +{ + return std::string("<") + .append(tag_) + .append(" ") + .append(attr_) + .append(">") + .append(content_) + .append(""); +} + +void removeAccessibilityTags(std::string& str){ + std::vector accessibilityTags = + {"protected internal", "private protected", "public", "private", "protected", "internal"}; + + std::stringstream ss(str), result; + std::string line; + + while(std::getline(ss, line)){ + + if (line.find('[') != 0) { + result << line << '\n'; + } + } + + str = result.str(); + boost::trim(str); + for (auto const& tag : accessibilityTags){ + if (str.find(tag) != std::string::npos) + { + str.erase(str.find(tag), tag.length() + 1); + } + } +} + +} +namespace cc +{ +namespace service +{ +namespace language +{ + +CsharpDiagram::CsharpDiagram( + std::shared_ptr db_, + std::shared_ptr datadir_, + const cc::webserver::ServerContext& context_) + : _db(db_), + _transaction(db_), + _projectHandler(db_, datadir_, context_) +{ +} + +void CsharpDiagram::getFunctionCallDiagram( + util::Graph& graph_, + const AstNodeInfo& centerNodeInfo_, + const std::vector& calleeNodeInfos_, + const std::vector& callerNodeInfos_) +{ + graph_.setAttribute("rankdir", "LR"); + + // Center node + AstNodeInfo nodeInfo = centerNodeInfo_; + removeAccessibilityTags(nodeInfo.astNodeValue); + nodeInfo.astNodeValue = nodeInfo.astNodeValue.substr(0,nodeInfo.astNodeValue.find('{')); + util::Graph::Node centerNode = addNode(graph_, nodeInfo); + decorateNode(graph_, centerNode, centerNodeDecoration); + + // Callees + + for (const auto& calleeNodeInfo : calleeNodeInfos_) + { + AstNodeInfo calleeInfo = calleeNodeInfo; + removeAccessibilityTags(calleeInfo.astNodeValue); + calleeInfo.astNodeValue = calleeInfo.astNodeValue.substr(0,calleeInfo.astNodeValue.find('{')); + util::Graph::Node calleeNode = addNode(graph_, calleeInfo); + decorateNode(graph_, centerNode, calleeNodeDecoration); + + if (!graph_.hasEdge(centerNode, calleeNode)) + { + util::Graph::Edge edge = graph_.createEdge(centerNode, calleeNode); + decorateEdge(graph_, edge, calleeEdgeDecoration); + } + } + + // Callers + + for (const auto& callerNodeInfo : callerNodeInfos_) + { + AstNodeInfo callerInfo = callerNodeInfo; + removeAccessibilityTags(callerInfo.astNodeValue); + callerInfo.astNodeValue = callerInfo.astNodeValue.substr(0,callerInfo.astNodeValue.find('{')); + util::Graph::Node callerNode = addNode(graph_, callerInfo); + decorateNode(graph_, centerNode, callerNodeDecoration); + + if (!graph_.hasEdge(centerNode, callerNode)) + { + util::Graph::Edge edge = graph_.createEdge(callerNode, centerNode); + decorateEdge(graph_, edge, callerEdgeDecoration); + } + } + _subgraphs.clear(); + } + +void CsharpDiagram::getDetailedClassDiagram( + util::Graph& graph_, + const AstNodeInfo& centerNodeInfo_, + const std::vector& propertyNodeInfos_, + const std::vector& methodNodeInfos_) +{ + graph_.setAttribute("rankdir", "BT"); + + // Center node - class + + AstNodeInfo nodeInfo = centerNodeInfo_; + removeAccessibilityTags(nodeInfo.astNodeValue); + nodeInfo.astNodeValue = nodeInfo.astNodeValue.substr(0,nodeInfo.astNodeValue.find('{')); + util::Graph::Node centerNode = addNode(graph_, nodeInfo); + + // Property and method/contructor nodes + + graph_.setNodeAttribute(centerNode,"label", + getDetailedClassNodeLabel(nodeInfo,propertyNodeInfos_,methodNodeInfos_), + true); + graph_.setNodeAttribute(centerNode,"shape", "none"); +} + +std::string CsharpDiagram::getDetailedClassNodeLabel( + const AstNodeInfo& centerNodeInfo_, + const std::vector& propertyNodeInfos_, + const std::vector& methodNodeInfos_) +{ + std::string colAttr = "border='0' align='left'"; + std::string label = ""; + + label.append(graphHtmlTag("tr", graphHtmlTag("td", + graphHtmlTag("font", + util::escapeHtml(centerNodeInfo_.astNodeValue), "color='white'"), + "colspan='2' SIDES='B' bgcolor='#316ECF' align='center'"))); + + //--- Data members of the class + + for (auto it = propertyNodeInfos_.begin(); it != propertyNodeInfos_.end(); ++it) + { + std::string astValueToShow = it->astNodeValue; + removeAccessibilityTags(astValueToShow); + astValueToShow = astValueToShow.substr(0,astValueToShow.find('{')); + + std::string visibility = visibilityToHtml(*it); + std::string content = memberContentToHtml(*it, + util::escapeHtml(astValueToShow)); + + std::string attr = colAttr; + if (it == propertyNodeInfos_.end() - 1) + attr = "border='1' align='left' SIDES='B'"; + + label += graphHtmlTag("tr", + graphHtmlTag("td", visibility, attr) + + graphHtmlTag("td", content, attr)); + } + + // Methods of the class + + for (const AstNodeInfo& node : methodNodeInfos_) + { + std::string visibility = visibilityToHtml(node); + + if (!node.astNodeValue.empty()) + { + std::string astValueToShow = node.astNodeValue; + removeAccessibilityTags(astValueToShow); + astValueToShow = astValueToShow.substr(0,astValueToShow.find('{')); + + std::string content = memberContentToHtml(node, + util::escapeHtml(astValueToShow)); + + label += graphHtmlTag("tr", + graphHtmlTag("td", visibility, colAttr) + + graphHtmlTag("td", content, colAttr)); + } + } + + label.append("
"); + + return label; +} + +std::string CsharpDiagram::visibilityToHtml(const AstNodeInfo& node_) +{ + if (contains(node_.tags, "Public")) + return graphHtmlTag("font", "+", "color='green'"); + if (contains(node_.tags, "Private")) + return graphHtmlTag("font", "-", "color='red'"); + if (contains(node_.tags, "Private protected")) + return graphHtmlTag("font", "-#", "color='red'"); + if (contains(node_.tags, "Protected")) + return graphHtmlTag("font", "#", "color='blue'"); + if (contains(node_.tags, "Internal")) + return graphHtmlTag("font", "~", "color='blue'"); + if (contains(node_.tags, "Protected internal")) + return graphHtmlTag("font", "#~", "color='blue'"); + + return ""; +} + +std::string CsharpDiagram::memberContentToHtml( + const AstNodeInfo& node_, + const std::string& content_) +{ + std::string startTags; + std::string endTags; + + if (contains(node_.tags, "Static")) + { + startTags += ""; + endTags.insert(0, ""); + } + + if (contains(node_.tags, "Virtual")) + { + startTags += ""; + endTags.insert(0, ""); + } + + return startTags + util::escapeHtml(content_) + endTags; +} + +util::Graph::Node CsharpDiagram::addNode( + util::Graph& graph_, + const AstNodeInfo& nodeInfo_) +{ + util::Graph::Node node + = graph_.getOrCreateNode(nodeInfo_.id, + addSubgraph(graph_, nodeInfo_.range.file)); + + graph_.setNodeAttribute(node, "label", nodeInfo_.astNodeValue); + + return node; +} + +std::string CsharpDiagram::getDetailedClassLegend() +{ + util::LegendBuilder builder("Detailed Class CsharpDiagram"); + + builder.addNode("class", classNodeDecoration); + builder.addNode("public data member", {{"shape", "none"}, + {"label", graphHtmlTag("font", "+", "color='green'")}}, true); + builder.addNode("private data member", {{"shape", "none"}, + {"label", graphHtmlTag("font", "-", "color='red'")}}, true); + builder.addNode("protected data member", {{"shape", "none"}, + {"label", graphHtmlTag("font", "#", "color='blue'")}}, true); + builder.addNode("internal data member", {{"shape", "none"}, + {"label", graphHtmlTag("font", "~", "color='blue'")}}, true); + builder.addNode("private protected data member", {{"shape", "none"}, + {"label", graphHtmlTag("font", "-#", "color='blue'")}}, true); + builder.addNode("protected internal data member", {{"shape", "none"}, + {"label", graphHtmlTag("font", "#~", "color='blue'")}}, true); + builder.addNode("static method or data member", {{"shape", "none"}, + {"label", "static"}}, true); + builder.addNode("virtual method", {{"shape", "none"}, + {"label", "virtual"}}, true); + + return builder.getOutput(); +} + +std::string CsharpDiagram::getFunctionCallLegend() +{ + util::LegendBuilder builder("Function Call CsharpDiagram"); + + builder.addNode("center function", centerNodeDecoration); + builder.addNode("called function", calleeNodeDecoration); + builder.addNode("caller function", callerNodeDecoration); + builder.addNode("virtual function", virtualNodeDecoration); + builder.addEdge("called", calleeEdgeDecoration); + builder.addEdge("caller", callerEdgeDecoration); + + return builder.getOutput(); +} + +util::Graph::Subgraph CsharpDiagram::addSubgraph( + util::Graph& graph_, + const core::FileId& fileId_) +{ + auto it = _subgraphs.find(fileId_); + + if (it != _subgraphs.end()) + return it->second; + + core::FileInfo fileInfo; + _projectHandler.getFileInfo(fileInfo, fileId_); + + util::Graph::Subgraph subgraph + = graph_.getOrCreateSubgraph("cluster_" + fileInfo.path); + + graph_.setSubgraphAttribute(subgraph, "id", fileInfo.id); + graph_.setSubgraphAttribute(subgraph, "label", fileInfo.path); + + _subgraphs.insert(it, std::make_pair(fileInfo.path, subgraph)); + + return subgraph; +} + +void CsharpDiagram::decorateNode( + util::Graph& graph_, + const util::Graph::Node& node_, + const Decoration& decoration_) const +{ + for (const auto& attr : decoration_) + graph_.setNodeAttribute(node_, attr.first, attr.second); +} + +void CsharpDiagram::decorateEdge( + util::Graph& graph_, + const util::Graph::Edge& edge_, + const Decoration& decoration_) const +{ + for (const auto& attr : decoration_) + graph_.setEdgeAttribute(edge_, attr.first, attr.second); +} + +void CsharpDiagram::decorateSubgraph( + util::Graph& graph_, + const util::Graph::Subgraph& subgraph_, + const Decoration& decoration_) const +{ + for (const auto& attr : decoration_) + graph_.setSubgraphAttribute(subgraph_, attr.first, attr.second); +} + +const CsharpDiagram::Decoration CsharpDiagram::centerNodeDecoration = { + {"style", "filled"}, + {"fillcolor", "gold"} +}; + +const CsharpDiagram::Decoration CsharpDiagram::calleeNodeDecoration = { + {"style", "filled"}, + {"fillcolor", "lightblue"} +}; + +const CsharpDiagram::Decoration CsharpDiagram::callerNodeDecoration = { + {"style", "filled"}, + {"fillcolor", "coral"} +}; + +const CsharpDiagram::Decoration CsharpDiagram::virtualNodeDecoration = { + {"shape", "diamond"}, + {"style", "filled"}, + {"fillcolor", "cyan"} +}; + +const CsharpDiagram::Decoration CsharpDiagram::calleeEdgeDecoration = { + {"color", "blue"} +}; + +const CsharpDiagram::Decoration CsharpDiagram::callerEdgeDecoration = { + {"color", "red"} +}; + +const CsharpDiagram::Decoration CsharpDiagram::classNodeDecoration = { + {"shape", "box"} +}; + +} +} +} \ No newline at end of file diff --git a/plugins/csharp/service/src/csharpdiagram.h b/plugins/csharp/service/src/csharpdiagram.h new file mode 100644 index 000000000..c5a82800b --- /dev/null +++ b/plugins/csharp/service/src/csharpdiagram.h @@ -0,0 +1,150 @@ +#ifndef CC_SERVICE_LANGUAGE_CSHARPDIAGRAM_H +#define CC_SERVICE_LANGUAGE_CSHARPDIAGRAM_H + +#include +#include +#include + +namespace cc +{ +namespace service +{ +namespace language +{ + +class CsharpDiagram +{ +public: + CsharpDiagram( + std::shared_ptr db_, + std::shared_ptr datadir_, + const cc::webserver::ServerContext& context_); + + void getFunctionCallDiagram( + util::Graph& graph_, + const AstNodeInfo& centerNodeInfo_, + const std::vector& calleeNodeInfos_, + const std::vector& callerNodeInfos_); + + /** + * This function creates legend for the Function call diagram. + * @return The generated legend as a string in SVG format. + */ + std::string getFunctionCallLegend(); + + /** + * This is a classical UML class diagram for the selected class and its + * direct children and parents. The nodes contain the methods and member + * variables with their visibility. + */ + void getDetailedClassDiagram( + util::Graph& graph_, + const AstNodeInfo& centerNodeInfo_, + const std::vector& propertyNodeInfos_, + const std::vector& methodNodeInfos_); + + /** + * This function creates legend for the Detailed class diagram. + * @return The generated legend as a string in SVG format. + */ + std::string getDetailedClassLegend(); + +private: + typedef std::vector> Decoration; + typedef std::pair GraphNodePair; + + /** + * This function adds a node which represents an AST node. The label of the + * node is the AST node value. A node associated with the file is added only + * once. If already added then the previous one is returned. + */ + util::Graph::Node addNode( + util::Graph& graph_, + const AstNodeInfo& nodeInfo_); + + /** + * This function adds a subgraph which represents a file. The label of the + * subgraph will be the file path and the subgraph will have a border. A + * subgraph associated with the file is added only once. If already added then + * the previous one is returned. + */ + util::Graph::Subgraph addSubgraph( + util::Graph& graph_, + const core::FileId& fileId_); + + /** + * This function creates node label for UML class diagram for the + * selected class. + */ + std::string getDetailedClassNodeLabel( + const AstNodeInfo& centerNodeInfo_, + const std::vector& propertyNodeInfos_, + const std::vector& methodNodeInfos_); + + /** + * This function return string representation visibility of an AST node + * in HTML format. + */ + std::string visibilityToHtml(const AstNodeInfo& node_); + + /** + * This function returns member content styled by their properties. + * (E.g.: static -> underline, virtual -> italic etc.) + */ + std::string memberContentToHtml( + const AstNodeInfo& node_, + const std::string& content_); + + /** + * This function decorates a graph node. + * @param graph_ A graph object. + * @param elem_ A graph node + * @param decoration_ A map which describes the style attributes. + */ + void decorateNode( + util::Graph& graph_, + const util::Graph::Node& node_, + const Decoration& decoration_) const; + + /** + * This function decorates a graph edge. + * @param graph_ A graph object. + * @param elem_ A graph edge + * @param decoration_ A map which describes the style attributes. + */ + void decorateEdge( + util::Graph& graph_, + const util::Graph::Edge& edge_, + const Decoration& decoration_) const; + + /** + * This function decorates a graph subgraph. + * @param graph_ A graph object. + * @param elem_ A graph subgraph + * @param decoration_ A map which describes the style attributes. + */ + void decorateSubgraph( + util::Graph& graph_, + const util::Graph::Subgraph& subgrap_, + const Decoration& decoration_) const; + + static const Decoration centerNodeDecoration; + static const Decoration calleeNodeDecoration; + static const Decoration callerNodeDecoration; + static const Decoration virtualNodeDecoration; + static const Decoration calleeEdgeDecoration; + static const Decoration callerEdgeDecoration; + static const Decoration classNodeDecoration; + + std::map _subgraphs; + + std::shared_ptr _db; + util::OdbTransaction _transaction; + core::ProjectServiceHandler _projectHandler; +}; + +} +} +} + +#endif diff --git a/plugins/csharp/service/src/csharpfilediagram.cpp b/plugins/csharp/service/src/csharpfilediagram.cpp new file mode 100644 index 000000000..2a8c2ba68 --- /dev/null +++ b/plugins/csharp/service/src/csharpfilediagram.cpp @@ -0,0 +1,320 @@ +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "csharpfilediagram.h" + + +namespace cc +{ +namespace service +{ +namespace language +{ + +typedef odb::query FileQuery; +typedef odb::result FileResult; +typedef std::map> Usages; +typedef std::map> DirectoryUsages; + +CsharpFileDiagram::CsharpFileDiagram( + std::shared_ptr db_, + std::shared_ptr datadir_, + const cc::webserver::ServerContext& context_) + : _db(db_), + _transaction(db_), + _projectHandler(db_, datadir_, context_) +{ +} + +void CsharpFileDiagram::getFileUsagesDiagram( + util::Graph& graph_, + const core::FileId& fileId_, + const Usages& useIds_, + const Usages& revUseIds_) +{ + core::FileInfo fileInfo; + _projectHandler.getFileInfo(fileInfo, fileId_); + util::Graph::Node currentNode = addNode(graph_, fileInfo); + decorateNode(graph_, currentNode, centerNodeDecoration); + + //create nodes for use cases + for (const auto& entry : useIds_) + { + core::FileId fileId = entry.first; + core::FileInfo fileInfo; + _projectHandler.getFileInfo(fileInfo, fileId); + util::Graph::Node currentNode = addNode(graph_, fileInfo); + + for (const auto& value : entry.second) + { + core::FileId fileId = value; + core::FileInfo fileInfo; + _projectHandler.getFileInfo(fileInfo, fileId); + util::Graph::Node toNode = addNode(graph_, fileInfo); + + util::Graph::Edge useEdge = graph_.createEdge(currentNode, toNode); + decorateEdge(graph_, useEdge, usagesEdgeDecoration); + + } + } + + //create nodes for revuse cases + for (const auto& entry : revUseIds_) + { + core::FileId fileId = entry.first; + core::FileInfo fileInfo; + _projectHandler.getFileInfo(fileInfo, fileId); + util::Graph::Node currentNode = addNode(graph_, fileInfo); + + for (const auto& value : entry.second) + { + core::FileId fileId = value; + core::FileInfo fileInfo; + _projectHandler.getFileInfo(fileInfo, fileId); + util::Graph::Node toNode = addNode(graph_, fileInfo); + + util::Graph::Edge useEdge = graph_.createEdge(currentNode, toNode); + decorateEdge(graph_, useEdge, revUsagesEdgeDecoration); + + } + } + + decorateNode(graph_, currentNode, centerNodeDecoration); +} + +std::string CsharpFileDiagram::getFileUsagesDiagramLegend() +{ + util::LegendBuilder builder("File Usages Diagram"); + + builder.addNode("center node", centerNodeDecoration); + builder.addNode("source file", sourceFileNodeDecoration); + + builder.addEdge("uses", usagesEdgeDecoration); + builder.addEdge("used by files", revUsagesEdgeDecoration); + + return builder.getOutput(); +} + +void CsharpFileDiagram::getExternalUsersDiagram( + util::Graph& graph_, + const core::FileId& fileId_, + const DirectoryUsages& dirRevUsages_) +{ + core::FileInfo fileInfo; + _projectHandler.getFileInfo(fileInfo, fileId_); + util::Graph::Node currentNode = addNode(graph_, fileInfo); + decorateNode(graph_, currentNode, centerNodeDecoration); + + //to get the directory tree + getSubsystemDependencyDiagram(graph_,fileId_); + + for (const auto& map : dirRevUsages_) + { + core::FileId fileId = map.first; + core::FileInfo fInfo; + _projectHandler.getFileInfo(fInfo, fileId); + util::Graph::Node dirNode = addNode(graph_, fInfo); + + for (const auto& innerMap : map.second) + { + for (const auto& revUseIds : innerMap) + { + for (const auto& revUseId : revUseIds.second) + { + core::FileInfo info; + + _projectHandler.getFileInfo(info, revUseId); + if (info.path.find(fileInfo.path + '/') == std::string::npos) + { + core::FileInfo externalDirInfo; + _projectHandler.getFileInfo(externalDirInfo, info.parent); + util::Graph::Node externalDirNode = addNode(graph_,externalDirInfo); + + if (!graph_.hasEdge(dirNode,externalDirNode)) + { + util::Graph::Edge edge = graph_.createEdge(dirNode,externalDirNode); + decorateEdge(graph_, edge, revUsagesEdgeDecoration); + } + } + } + } + } + } +} + +std::string CsharpFileDiagram::getExternalUsersDiagramLegend() +{ + util::LegendBuilder builder("External Users Diagram"); + + builder.addNode("center file", centerNodeDecoration); + builder.addNode("directory", directoryNodeDecoration); + + builder.addEdge("sub directory", subdirEdgeDecoration); + builder.addEdge("used by", revUsagesEdgeDecoration); + + return builder.getOutput(); +} + +void CsharpFileDiagram::getSubsystemDependencyDiagram( + util::Graph& graph_, + const core::FileId& fileId_) +{ + core::FileInfo fileInfo; + _projectHandler.getFileInfo(fileInfo, fileId_); + util::Graph::Node currentNode = addNode(graph_, fileInfo); + decorateNode(graph_, currentNode, centerNodeDecoration); + decorateNode(graph_, currentNode, directoryNodeDecoration); + + std::set subdirs = util::bfsBuild(graph_, currentNode, + std::bind(&CsharpFileDiagram::getSubDirs, this, std::placeholders::_1, + std::placeholders::_2), {}, subdirEdgeDecoration); + + subdirs.insert(currentNode); +} + +std::string CsharpFileDiagram::getSubsystemDependencyDiagramLegend() +{ + util::LegendBuilder builder("Subsystem Dependency Diagram"); + + builder.addNode("center file", centerNodeDecoration); + builder.addNode("directory", directoryNodeDecoration); + + builder.addEdge("sub directory", subdirEdgeDecoration); + + return builder.getOutput(); +} + +std::vector CsharpFileDiagram::getSubDirs( + util::Graph& graph_, + const util::Graph::Node& node_) +{ + std::vector usages; + + _transaction([&, this]{ + FileResult sub = _db->query( + FileQuery::parent == std::stoull(node_) && + FileQuery::type == model::File::DIRECTORY_TYPE); + + for (const model::File& subdir : sub) + { + core::FileInfo fileInfo; + _projectHandler.getFileInfo(fileInfo, std::to_string(subdir.id)); + + usages.push_back(addNode(graph_, fileInfo)); + } + }); + + return usages; +} + +std::vector CsharpFileDiagram::getNodesFromIds( + util::Graph& graph, + const std::vector& fileIds) +{ + std::vector usages; + + for (const core::FileId& fileId: fileIds) + { + core::FileInfo fileInfo; + _projectHandler.getFileInfo(fileInfo, fileId); + + usages.push_back(addNode(graph, fileInfo)); + } + + return usages; +} + +util::Graph::Node CsharpFileDiagram::addNode( + util::Graph& graph_, + const core::FileInfo& fileInfo_) +{ + util::Graph::Node node = graph_.getOrCreateNode(fileInfo_.id); + graph_.setNodeAttribute(node, "label", getLastNParts(fileInfo_.path, 3)); + + if (fileInfo_.type == model::File::DIRECTORY_TYPE) + { + decorateNode(graph_, node, directoryNodeDecoration); + } + else if (fileInfo_.type == "CS") + { + std::string ext = boost::filesystem::extension(fileInfo_.path); + std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower); + decorateNode(graph_, node, sourceFileNodeDecoration); + } + + return node; +} + +void CsharpFileDiagram::decorateNode( + util::Graph& graph_, + const util::Graph::Node& node_, + const Decoration& decoration_) const +{ + for (const auto& attr : decoration_) + graph_.setNodeAttribute(node_, attr.first, attr.second); +} + +void CsharpFileDiagram::decorateEdge( + util::Graph& graph_, + const util::Graph::Edge& edge_, + const Decoration& decoration_) const +{ + for (const auto& attr : decoration_) + graph_.setEdgeAttribute(edge_, attr.first, attr.second); +} + +std::string CsharpFileDiagram::getLastNParts(const std::string& path_, std::size_t n_) +{ + if (path_.empty() || n_ == 0) + return ""; + + std::size_t p; + for (p = path_.rfind('/'); + --n_ > 0 && p - 1 < path_.size(); + p = path_.rfind('/', p - 1)); + + return p > 0 && p < path_.size() ? "..." + path_.substr(p) : path_; +} + +const CsharpFileDiagram::Decoration CsharpFileDiagram::centerNodeDecoration = { + {"shape", "ellipse"}, + {"style", "filled"}, + {"fillcolor", "gold"}, + {"fontcolor", "black"} +}; + +const CsharpFileDiagram::Decoration CsharpFileDiagram::sourceFileNodeDecoration = { + {"shape", "box"}, + {"style", "filled"}, + {"fillcolor", "#116db6"}, + {"fontcolor", "white"} +}; + +const CsharpFileDiagram::Decoration CsharpFileDiagram::directoryNodeDecoration = { + {"shape", "folder"} +}; + +const CsharpFileDiagram::Decoration CsharpFileDiagram::usagesEdgeDecoration = { + {"label", "uses"} +}; + +const CsharpFileDiagram::Decoration CsharpFileDiagram::revUsagesEdgeDecoration = { + {"label", "used by"} +}; + +const CsharpFileDiagram::Decoration CsharpFileDiagram::subdirEdgeDecoration = { + {"label", "subdir"}, + {"color", "green"} +}; + +} // language +} // service +} // cc \ No newline at end of file diff --git a/plugins/csharp/service/src/csharpfilediagram.h b/plugins/csharp/service/src/csharpfilediagram.h new file mode 100644 index 000000000..411acd21f --- /dev/null +++ b/plugins/csharp/service/src/csharpfilediagram.h @@ -0,0 +1,148 @@ +#ifndef CC_SERVICE_LANGUAGE_CSHARPFILEDIAGRAM_H +#define CC_SERVICE_LANGUAGE_CSHARPFILEDIAGRAM_H + +#include +#include +#include + +namespace cc +{ +namespace service +{ +namespace language +{ + +typedef std::map> Usages; +typedef std::map> DirectoryUsages; + +class CsharpFileDiagram +{ +public: + CsharpFileDiagram( + std::shared_ptr db_, + std::shared_ptr datadir_, + const cc::webserver::ServerContext& context_); + + /** + * This diagram shows directories (modules) that are users of the + * queried module. + */ + void getExternalUsersDiagram( + util::Graph& graph_, + const core::FileId& fileId_, + const DirectoryUsages& dirRevUsages_); + + /** + * This function creates legend for the External users diagram. + * @return The generated legend as a string in SVG format. + */ + std::string getExternalUsersDiagramLegend(); + + /** + * This diagram shows of the aggregation and association + * related file "use" and "used" dependencies. + */ + void getFileUsagesDiagram( + util::Graph& graph_, + const core::FileId& fileId_, + const Usages& useIds_, + const Usages& revUseIds_); + + /** + * This function creates legend for the Include dependency diagram. + * @return The generated legend as a string in SVG format. + */ + std::string getFileUsagesDiagramLegend(); + + /** + * This diagram shows the directories relationship between the subdirectories + * of the queried module. This diagram is useful to understand the + * relationships of the subdirectories (submodules) of a module. + */ + void getSubsystemDependencyDiagram( + util::Graph& graph_, + const core::FileId& fileId_); + + /** + * This function creates legend for the Subsystem dependency diagram. + * @return The generated legend as a string in SVG format. + */ + std::string getSubsystemDependencyDiagramLegend(); + +private: + typedef std::vector> Decoration; + + /** + * This function gathers the fileInfo related to the given file IDs + * and returns a list of nodes using the file infos. + */ + std::vector getNodesFromIds( + util::Graph& graph, + const std::vector& fileIds); + + /** + * This function adds a node which represents a File node. The label of the + * node is the file name. + */ + util::Graph::Node addNode( + util::Graph& graph_, + const core::FileInfo& fileInfo_); + + /** + * This function decorates a graph node. + * @param graph_ A graph object. + * @param elem_ A graph node + * @param decoration_ A map which describes the style attributes. + */ + void decorateNode( + util::Graph& graph_, + const util::Graph::Node& node_, + const Decoration& decoration_) const; + + /** + * This function decorates a graph edge. + * @param graph_ A graph object. + * @param elem_ A graph edge + * @param decoration_ A map which describes the style attributes. + */ + void decorateEdge( + util::Graph& graph_, + const util::Graph::Edge& edge_, + const Decoration& decoration_) const; + + /** + * Returns the last `n` parts of the path with a '...' if the part size is + * larger than `n`. + * (E.g.: path = `/a/b/c/d` and n = `3` then the is result = .../b/c/d) + */ + std::string getLastNParts(const std::string& path_, std::size_t n_); + + /** + * This function creates graph nodes for sub directories of the actual file + * node and returns the created graph nodes. + * @param graph_ A graph object. + * @param fileNode_ Graph file node object which represents a file object. + * @return Subdirectory graph nodes. + */ + std::vector getSubDirs( + util::Graph& graph_, + const util::Graph::Node& fileNode_); + + static const Decoration centerNodeDecoration; + static const Decoration sourceFileNodeDecoration; + static const Decoration directoryNodeDecoration; + + static const Decoration usagesEdgeDecoration; + static const Decoration revUsagesEdgeDecoration; + static const Decoration subdirEdgeDecoration; + + std::shared_ptr _db; + util::OdbTransaction _transaction; + core::ProjectServiceHandler _projectHandler; +}; + +} // language +} // service +} // cc + +#endif // CC_SERVICE_LANGUAGE_FILEDIAGRAM_H diff --git a/plugins/csharp/service/src/csharpservice.cpp b/plugins/csharp/service/src/csharpservice.cpp index 7d44b417d..6eb1f33b6 100644 --- a/plugins/csharp/service/src/csharpservice.cpp +++ b/plugins/csharp/service/src/csharpservice.cpp @@ -4,6 +4,13 @@ #include #include +#include +#include +#include + +#include "csharpfilediagram.h" +#include "csharpdiagram.h" + namespace cc { namespace service @@ -11,6 +18,9 @@ namespace service namespace language { typedef odb::query FileQuery; +typedef odb::result FileResult; +typedef std::map> Usages; +typedef std::map> DirectoryUsages; namespace fs = boost::filesystem; namespace bp = boost::process; namespace pt = boost::property_tree; @@ -71,9 +81,8 @@ void CsharpServiceHandler::getAstNodeInfo( FileQuery::path == return_.range.file); }); std::stringstream ss; - ss << file; + ss << file->id; return_.range.file = ss.str(); - //LOG(info) << "csharpQuery.getAstNodeInfo: file = " << return_.range.file; } void CsharpServiceHandler::getAstNodeInfoByPosition( @@ -85,6 +94,7 @@ void CsharpServiceHandler::getAstNodeInfoByPosition( FileQuery::id == std::stoull(fpos_.file)); }); _csharpQueryHandler.getAstNodeInfoByPosition(return_, file->path, fpos_.pos); + return_.range.file = fpos_.file; //so that getFileInfo requests contain the file id. } void CsharpServiceHandler::getSourceText( @@ -98,7 +108,7 @@ void CsharpServiceHandler::getSourceText( return_ = _transaction([&, this](){ model::FilePtr file = _db->query_one( - FileQuery::id == std::stoull(fileRange.file)); + FileQuery::path == /*std::stoull(*/fileRange.file/*)*/); // id volt if (!file) { return std::string(); @@ -134,7 +144,7 @@ void CsharpServiceHandler::getDiagramTypes( const core::AstNodeId& astNodeId_) { LOG(info) << "getDiagramTypes"; - //csharpQueryHandler.getDiagramTypes(return_, astNodeId_); + _csharpQueryHandler.getDiagramTypes(return_, astNodeId_); } void CsharpServiceHandler::getDiagram( @@ -143,7 +153,49 @@ void CsharpServiceHandler::getDiagram( const std::int32_t diagramId_) { LOG(info) << "getDiagram"; - //csharpQueryHandler.getDiagram(return_, astNodeId_, diagramId_); + CsharpDiagram diagram(_db,_datadir,_context); + util::Graph graph; + + switch (diagramId_) + { + case FUNCTION_CALL: + { + // Center node + AstNodeInfo centerInfo; + getAstNodeInfo(centerInfo,astNodeId_); + + // Callee nodes + std::vector calleeInfos; + getReferences(calleeInfos,astNodeId_,(int)ReferenceType::CALLEE,{}); + + // Caller nodes + std::vector callerInfos; + getReferences(callerInfos,astNodeId_,(int)ReferenceType::CALLER,{}); + + diagram.getFunctionCallDiagram(graph,centerInfo,calleeInfos,callerInfos); + break; + } + case DETAILED_CLASS: + { + // Center node + AstNodeInfo centInfo; + getAstNodeInfo(centInfo,astNodeId_); + + //Data members - property nodes + std::vector propertyInfos; + getReferences(propertyInfos, astNodeId_,(int)ReferenceType::DATA_MEMBER,{}); + + // Method nodes + std::vector methodInfos; + getReferences(methodInfos,astNodeId_,(int)ReferenceType::METHOD,{}); + + diagram.getDetailedClassDiagram(graph,centInfo,propertyInfos,methodInfos); + break; + } + } + + if (graph.nodeCount() != 0) + return_ = graph.output(util::Graph::SVG); } void CsharpServiceHandler::getDiagramLegend( @@ -151,6 +203,19 @@ void CsharpServiceHandler::getDiagramLegend( const std::int32_t diagramId_) { LOG(info) << "getDiagramLegend"; + + CsharpDiagram diagram(_db,_datadir, _context); + + switch (diagramId_) + { + case FUNCTION_CALL: + return_ = diagram.getFunctionCallLegend(); + break; + + case DETAILED_CLASS: + return_ = diagram.getDetailedClassLegend(); + break; + } } void CsharpServiceHandler::getFileDiagramTypes( @@ -158,6 +223,24 @@ void CsharpServiceHandler::getFileDiagramTypes( const core::FileId& fileId_) { LOG(info) << "getFileDiagramTypes"; + + model::FilePtr file = _transaction([&, this](){ + return _db->query_one( + FileQuery::id == std::stoull(fileId_)); + }); + + if (file) + { + if (file->type == model::File::DIRECTORY_TYPE) + { + return_["Internal architecture of this module"] = SUBSYSTEM_DEPENDENCY; + return_["Users of this module"] = EXTERNAL_USERS; + } + else if (file->type == "CS") + { + return_["File usage"] = FILE_USAGES; + } + } } void CsharpServiceHandler::getFileDiagram( @@ -166,6 +249,93 @@ void CsharpServiceHandler::getFileDiagram( const int32_t diagramId_) { LOG(info) << "getFileDiagram"; + + CsharpFileDiagram diagram(_db,_datadir, _context); + util::Graph graph; + graph.setAttribute("rankdir", "LR"); + + switch (diagramId_){ + case FILE_USAGES: + { + Usages useIds; + _csharpQueryHandler.getFileUsages(useIds,fileId_,false); + Usages revUseIds; + _csharpQueryHandler.getFileUsages(revUseIds,fileId_,true); + + diagram.getFileUsagesDiagram(graph,fileId_,useIds,revUseIds); + + break; + } + case SUBSYSTEM_DEPENDENCY: + { + diagram.getSubsystemDependencyDiagram(graph,fileId_); + break; + } + case EXTERNAL_USERS: + { + DirectoryUsages dirRevUsages; + + //This is the main directory to which the diagram is called upon. + model::FilePtr directory = _transaction([&,this]{ + return _db->query_one( + FileQuery::id == std::stoull(fileId_) + ); + }); + + //This will contain all the directories from the project + std::vector directories; + util::OdbTransaction {_db} ([&]() { + FileResult res = _db->query( + FileQuery::type == model::File::DIRECTORY_TYPE); + for (auto fp : res) + directories.push_back(std::make_shared(std::move(fp))); + }); + + //Sub will contain all the directories which are subdirectories + //of main directory, including the main directory. + //Checking is done with the paths. + std::vector sub; + sub.push_back(directory); + for (const auto& dir : directories) + { + if (dir->path.find(directory->path + '/') != std::string::npos) + sub.push_back(dir); + } + + // Iterate on subddirectories and add a BFS to each CS file + // under the subdir. + // Gather for each subdir every BFS for every CS file into + // dirRevUsages. + std::vector css; + std::vector revs; + Usages rev; + for (const model::FilePtr& subdir : sub) + { + util::OdbTransaction {_db} ([&](){ + FileResult res = _db->query( + FileQuery::parent == subdir->id && + FileQuery::type == "CS"); + for (auto fp : res) + css.push_back(std::make_shared(std::move(fp))); + }); + for (const model::FilePtr& cs : css) + { + std::string id = std::to_string(cs->id); + _csharpQueryHandler.getFileUsages(rev,id,true); + revs.push_back(rev); + rev.clear(); + } + dirRevUsages[std::to_string(subdir->id)] = revs; + revs.clear(); + css.clear(); + } + diagram.getExternalUsersDiagram(graph,fileId_,dirRevUsages); + break; + } + } + + if (graph.nodeCount() != 0) + return_ = graph.output(util::Graph::SVG); } void CsharpServiceHandler::getFileDiagramLegend( @@ -173,6 +343,23 @@ void CsharpServiceHandler::getFileDiagramLegend( const std::int32_t diagramId_) { LOG(info) << "getFileDiagramLegend"; + CsharpFileDiagram diagram(_db, _datadir, _context); + + switch (diagramId_) + { + + case EXTERNAL_USERS: + return_ = diagram.getExternalUsersDiagramLegend(); + break; + + case FILE_USAGES: + return_ = diagram.getFileUsagesDiagramLegend(); + break; + + case SUBSYSTEM_DEPENDENCY: + return_ = diagram.getSubsystemDependencyDiagramLegend(); + break; + } } void CsharpServiceHandler::getReferenceTypes( @@ -197,8 +384,8 @@ void CsharpServiceHandler::getReferences( const std::int32_t referenceId_, const std::vector& tags_) { - //LOG(info) << "getReferences"; - _csharpQueryHandler.getReferences(return_, astNodeId_, referenceId_, tags_); + LOG(info) << "getReferences"; + _csharpQueryHandler.getReferences(return_, astNodeId_, referenceId_, {}); std::vector ret; for (AstNodeInfo nodeinfo : return_) { @@ -288,7 +475,7 @@ void CsharpServiceHandler::getSyntaxHighlight( while (std::getline(s, line)) content.push_back(line); }); - csharpQueryHandler.getSyntaxHighlight(return_, range_, content); + _csharpQueryHandler.getSyntaxHighlight(return_, range_, content); */ } diff --git a/plugins/csharp/service/src_csharp/CSharpQueryHandler.cs b/plugins/csharp/service/src_csharp/CSharpQueryHandler.cs index 0a422de3e..fbacee3bb 100644 --- a/plugins/csharp/service/src_csharp/CSharpQueryHandler.cs +++ b/plugins/csharp/service/src_csharp/CSharpQueryHandler.cs @@ -143,6 +143,17 @@ private List queryDeclarators(CsharpAstNode astNode) } } + private List queryDeclaratorsForCodeBites(CsharpAstNode astNode) + { + var ret = dbContext.CsharpEtcEntitys + .Where(e => e.AstNode.Id == astNode.Id && + e.DeclaratorNodeId == 1) + .Select(e => e.AstNode) + .ToList(); + + return ret; + } + private List queryEvals(CsharpAstNode astNode) { var ret = @@ -193,6 +204,7 @@ from invoc in dbContext.CsharpEtcEntitys join node in dbContext.CsharpAstNodes on invoc.DeclaratorNodeId equals node.Id where node.AstSymbolType == AstSymbolTypeEnum.Method + && invoc.DeclaratorNodeId != invoc.AstNode.Id && invoc.AstNode.Path == astNode.Path && invoc.AstNode.Location_range_start_line >= astNode.Location_range_start_line && invoc.AstNode.Location_range_end_line <= astNode.Location_range_end_line @@ -207,6 +219,7 @@ from invoc in dbContext.CsharpEtcEntitys join node in dbContext.CsharpAstNodes on invoc.DeclaratorNodeId equals node.Id where node.AstSymbolType == AstSymbolTypeEnum.Method + && invoc.DeclaratorNodeId != invoc.AstNode.Id && invoc.AstNode.Path == astNode.Path && invoc.AstNode.Location_range_start_line >= astNode.Location_range_start_line && invoc.AstNode.Location_range_end_line <= astNode.Location_range_end_line @@ -217,7 +230,8 @@ on invoc.DeclaratorNodeId equals node.Id private List queryCallers(CsharpAstNode astNode) { var invocations = dbContext.CsharpEtcEntitys - .Where(e => e.DeclaratorNodeId == astNode.Id) + .Where(e => e.DeclaratorNodeId == astNode.Id && + e.DeclaratorNodeId != e.AstNode.Id) .Select(e => e.AstNode); var ret = from invoc in invocations @@ -258,7 +272,8 @@ private List queryEnumConsts(CsharpAstNode astNode) private List queryMethods(CsharpAstNode astNode) { var ret = dbContext.CsharpMethods - .Where(e => e.ParentNode.Id == astNode.Id) + .Where(e => e.ParentNode.Id == astNode.Id + && e.MethodType != MethodTypeEnum.Accessor) .Select(e => e.AstNode) .ToList(); return ret; @@ -289,7 +304,7 @@ private List queryEvents(CsharpAstNode astNode) CancellationToken cancellationToken = default(CancellationToken)) { System.Console.WriteLine("[CSharpService] getAstNodeInfoAsync"); - return await Task.FromResult(new language.AstNodeInfo()); + return await Task.FromResult(createAstNodeInfo(queryCsharpAstNode(astNodeId))); } public async Task getAstNodeInfoByPositionAsync(string path_, @@ -574,7 +589,7 @@ public async Task getReferenceCountAsync(string astNodeId, int referenceId, int referenceId, List tags, CancellationToken cancellationToken = default(CancellationToken)) { - var node = queryCsharpAstNode(astNodeId); + var node = queryCsharpAstNode(astNodeId); var ret = new List(); switch ((ReferenceType)referenceId) { @@ -582,6 +597,8 @@ public async Task getReferenceCountAsync(string astNodeId, int referenceId, ret = createAstNodeInfoList(queryInvocations(node)); break; case ReferenceType.DEFINITION: + ret = createAstNodeInfoList(queryDeclarators(node)); + break; case ReferenceType.DECLARATION: ret = createAstNodeInfoList(queryDeclarators(node)); break; @@ -635,6 +652,7 @@ public async Task getReferenceCountAsync(string astNodeId, int referenceId, " ReferenceType is unhandled"); break; } + return await Task.FromResult(ret); } @@ -664,21 +682,99 @@ public async Task getFileReferenceCountAsync(string path, int referenceId, public async Task> getDiagramTypesAsync(string astNodeId, CancellationToken cancellationToken = default(CancellationToken)) { + var node = queryCsharpAstNode(astNodeId); + + switch (node.AstSymbolType) + { + case AstSymbolTypeEnum.Method: + return await Task.FromResult(new Dictionary{ {"Function call diagram", (int)DiagramType.FUNCTION_CALL} }); + case AstSymbolTypeEnum.Class: + return await Task.FromResult(new Dictionary{ {"Detailed class diagram", (int)DiagramType.DETAILED_CLASS} }); + } + return await Task.FromResult(new Dictionary()); } - public async Task getDiagramAsync(string astNodeId, int diagramId, + public async Task> getSyntaxHighlightAsync(FileRange range, + List content, CancellationToken cancellationToken = default(CancellationToken)) { - return await Task.FromResult("Diagram"); + return await Task.FromResult(new List()); } - public async Task> getSyntaxHighlightAsync(FileRange range, - List content, + public async Task>> getFileUsagesAsync(string fileId, bool reverse = false, CancellationToken cancellationToken = default(CancellationToken)) { - return await Task.FromResult(new List()); + if (!reverse) + { + return await Task.FromResult(BFSBuild(fileId,getFileUsageIds)); + } + else + { + return await Task.FromResult(BFSBuild(fileId,getFileRevUsageIds)); + } + } + + private List getFileUsageIds(string fileId) + { + //Gather files(IDs) which our file uses + return dbContext.CsharpEdges + .Where(a => a.From.ToString() == fileId && + a.Type == EdgeType.USE) + .Select(a => a.To.ToString()) + .ToList(); } + private List getFileRevUsageIds(string fileId) + { + //Gather files(IDs) which use our file + return dbContext.CsharpEdges + .Where(a => a.To.ToString() == fileId && + a.Type == EdgeType.USE) + .Select(a => a.From.ToString()) + .ToList(); + } + + public static Dictionary> BFSBuild( + string startFile, + Func> relations, + int level = -1) + { + var visitedFiles = new Dictionary>(); + visitedFiles[startFile] = new List(); + + if (level < -1) + { + return visitedFiles; + } + + int currentLevel = 0; + Queue queue = new Queue(); + queue.Enqueue(startFile); + + bool walkLevel = true; + while (queue.Count > 0 && walkLevel) + { + string currentFile = queue.Dequeue(); + + foreach (string to in relations(currentFile)) + { + if (!visitedFiles.ContainsKey(to)) + { + visitedFiles[to] = new List(); + queue.Enqueue(to); + } + visitedFiles[currentFile].Add(to); + } + + currentLevel++; + if (level != -1) + { + walkLevel = currentLevel != level; + } + } + + return visitedFiles; + } } \ No newline at end of file diff --git a/plugins/csharp/service/src_csharp/CSharpServiceEnums.cs b/plugins/csharp/service/src_csharp/CSharpServiceEnums.cs index 8046956b6..93eeefe70 100644 --- a/plugins/csharp/service/src_csharp/CSharpServiceEnums.cs +++ b/plugins/csharp/service/src_csharp/CSharpServiceEnums.cs @@ -100,6 +100,8 @@ inclusion directive. */ enum DiagramType { +FILE_USAGES, + FUNCTION_CALL, /*!< In the function call diagram the nodes are functions and the edges are the function calls between them. The diagram also displays some dynamic information such as virtual function calls. */ diff --git a/plugins/csharp/service/src_csharp/csharpservice.csproj b/plugins/csharp/service/src_csharp/csharpservice.csproj index c40923804..b8525551d 100644 --- a/plugins/csharp/service/src_csharp/csharpservice.csproj +++ b/plugins/csharp/service/src_csharp/csharpservice.csproj @@ -12,6 +12,7 @@ + diff --git a/plugins/csharp/webgui/js/csharpDiagram.js b/plugins/csharp/webgui/js/csharpDiagram.js index 32b3c7caf..69915e9eb 100644 --- a/plugins/csharp/webgui/js/csharpDiagram.js +++ b/plugins/csharp/webgui/js/csharpDiagram.js @@ -87,7 +87,7 @@ function (topic, Menu, MenuItem, PopupMenuItem, model, viewHandler) { if (Object.keys(diagramTypes).length !== 0) return new PopupMenuItem({ - label : 'C++ Diagrams', + label : 'C# Diagrams', popup : submenu }); } diff --git a/plugins/csharp/webgui/js/csharpMenu.js b/plugins/csharp/webgui/js/csharpMenu.js index bd95aca1b..666292b65 100644 --- a/plugins/csharp/webgui/js/csharpMenu.js +++ b/plugins/csharp/webgui/js/csharpMenu.js @@ -136,11 +136,10 @@ function (topic, Menu, MenuItem, PopupMenuItem, astHelper, model, urlHandler, vi } })); - if (Object.keys(diagramTypes).length !== 0) - return new PopupMenuItem({ - label : 'Diagrams', - popup : submenu - }); + return new PopupMenuItem({ + label : 'C# Diagrams', + popup : submenu + }); } }; diff --git a/webgui/scripts/codecompass/view/codeBites.js b/webgui/scripts/codecompass/view/codeBites.js index dbaea2cf7..b16526bda 100644 --- a/webgui/scripts/codecompass/view/codeBites.js +++ b/webgui/scripts/codecompass/view/codeBites.js @@ -50,6 +50,11 @@ function (declare, array, dom, style, topic, on, ContentPane, ResizeHandle, */ var colorIdx = 0; + /** + * This element contains the data related to the current file. + */ + var fileInfo = null; + /** * Default properties of boxes. */ @@ -91,7 +96,7 @@ function (declare, array, dom, style, topic, on, ContentPane, ResizeHandle, //--- Set content ---// - var fileInfo = model.project.getFileInfo(astNodeInfo.range.file); + fileInfo = model.project.getFileInfo(astNodeInfo.range.file); languageService = model.getLanguageService(fileInfo.type); if (astNodeInfo.astNodeType !== 'Definition') @@ -117,18 +122,29 @@ function (declare, array, dom, style, topic, on, ContentPane, ResizeHandle, dom.place(newElement.domNode, panel.domNode); - if (parent) - newElement.connection = panel._jsPlumbInstance.connect({ - source : parent.domNode, - target : newElement.domNode, - paintStyle : { stroke : colors[colorIdx], strokeWidth : 2 }, - Anchors : ['Perimeter', { shape : 'Ellipse' }], - Endpoint : ['Dot', { radius : 1 }], - overlays : [['Label', { - label : astNodeInfo.astNodeValue, - cssClass : 'cb-label cb-label-' + colorIdx - }]] - }); + if (parent){ + if (fileInfo.type === "CS"){ + newElement.connection = panel._jsPlumbInstance.connect({ + source : parent.domNode, + target : newElement.domNode, + paintStyle : { stroke : colors[colorIdx], strokeWidth : 2 } + }); + } + else{ + newElement.connection = panel._jsPlumbInstance.connect({ + source : parent.domNode, + target : newElement.domNode, + paintStyle : { stroke : colors[colorIdx], strokeWidth : 2 }, + Anchors : ['Perimeter', { shape : 'Ellipse' }], + Endpoint : ['Dot', { radius : 1 }], + overlays : [['Label', { + label : astNodeInfo.astNodeValue, + cssClass : 'cb-label cb-label-' + colorIdx + }]] + }); + } + } + if (window.gtag) { window.gtag ('event', 'code_bites', { @@ -353,15 +369,17 @@ function (declare, array, dom, style, topic, on, ContentPane, ResizeHandle, astNodeInfo.id, refTypes["Definition"])[0]; //--- Check if it's necessary to open a new box ---// - - if (astNodeInfo.id === defAstNodeInfo.id) - return; - - if (hasRow(this.row + 1) && - array.some(elementMatrix[this.row + 1], function (element) { - return element.astNodeInfo.id === defAstNodeInfo.id; - })) - return; + + if (fileInfo.type !== "CS"){ + if (astNodeInfo.id === defAstNodeInfo.id) + return; + + if (hasRow(this.row + 1) && + array.some(elementMatrix[this.row + 1], function (element) { + return element.astNodeInfo.id === defAstNodeInfo.id; + })) + return; + } //--- Color selection and open new box ---//