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("")
+ .append(tag_)
+ .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