diff --git a/.github/scripts/ubuntu-22.04/setup_build.sh b/.github/scripts/ubuntu-22.04/setup_build.sh index 99627a015..33aa55739 100755 --- a/.github/scripts/ubuntu-22.04/setup_build.sh +++ b/.github/scripts/ubuntu-22.04/setup_build.sh @@ -1,8 +1,10 @@ #!/bin/bash # Install required packages for CodeCompass build -sudo apt install git cmake make g++ libboost-all-dev \ +sudo apt-get install --yes \ + git cmake make g++ libboost-all-dev \ llvm-15-dev clang-15 libclang-15-dev \ gcc-11-plugin-dev thrift-compiler libthrift-dev \ default-jdk libssl-dev libgraphviz-dev libmagic-dev libgit2-dev exuberant-ctags doxygen \ - libldap2-dev libgtest-dev \ No newline at end of file + libldap2-dev libgtest-dev \ + dotnet-sdk-8.0 diff --git a/.gitignore b/.gitignore index 66ec4b2d1..b3a52364a 100644 --- a/.gitignore +++ b/.gitignore @@ -9,10 +9,8 @@ nbproject/ # Vim *.swp - ## Build folders build/ build_*/ install/ install_*/ - diff --git a/FindThrift.cmake b/FindThrift.cmake index 0a44c0fde..6e654d5d9 100644 --- a/FindThrift.cmake +++ b/FindThrift.cmake @@ -15,7 +15,7 @@ find_path(libthrift_INCLUDE_DIR find_library(libthrift_LIBRARY NAMES thrift libthrift HINTS - ${THIRFT_LIBRARY_PATH} + ${THRIFT_LIBRARY_PATH} ${PC_LIBTHIRFT_LIBRARY_DIRS}) find_program(thrift_BIN diff --git a/docker/dev/Dockerfile b/docker/dev/Dockerfile index 1619c9bd5..3adcf5d51 100644 --- a/docker/dev/Dockerfile +++ b/docker/dev/Dockerfile @@ -8,6 +8,7 @@ ARG DEBIAN_FRONTEND=noninteractive # CodeCompass development dependencies. RUN set -x && apt-get update -qq \ && apt-get -y install --no-install-recommends \ + wget \ cmake make \ default-jdk \ universal-ctags \ @@ -27,6 +28,7 @@ RUN set -x && apt-get update -qq \ libsqlite3-dev \ libssl-dev \ llvm-15 clang-15 llvm-15-dev libclang-15-dev \ + dotnet-sdk-8.0 \ thrift-compiler libthrift-dev \ postgresql-server-dev-14 \ postgresql-14 && \ diff --git a/docker/runtime/Dockerfile b/docker/runtime/Dockerfile index 49b87eb29..6d455a443 100644 --- a/docker/runtime/Dockerfile +++ b/docker/runtime/Dockerfile @@ -56,6 +56,7 @@ RUN set -x && apt-get update -qq && \ curl ca-certificates gnupg \ wget \ llvm-15 \ + dotnet-sdk-8.0 \ libboost-filesystem-dev libboost-log-dev libboost-program-options-dev \ default-jre \ libgit2-dev \ diff --git a/docker/web/Dockerfile b/docker/web/Dockerfile index 4780bb7ec..c9ade42aa 100644 --- a/docker/web/Dockerfile +++ b/docker/web/Dockerfile @@ -17,7 +17,9 @@ ARG DEBIAN_FRONTEND=noninteractive RUN set -x && apt-get update -qq \ && apt-get install -qqy --no-install-recommends \ + wget \ llvm-15 \ + dotnet-sdk-8.0 \ libboost-filesystem-dev libboost-log-dev libboost-program-options-dev \ libsqlite3-dev \ postgresql-server-dev-14 \ diff --git a/plugins/csharp/.gitignore b/plugins/csharp/.gitignore new file mode 100644 index 000000000..239ae2c95 --- /dev/null +++ b/plugins/csharp/.gitignore @@ -0,0 +1,5 @@ +# C# +bin/ +obj/ +*.out +*.bak \ No newline at end of file diff --git a/plugins/csharp/CMakeLists.txt b/plugins/csharp/CMakeLists.txt new file mode 100644 index 000000000..121a8d43f --- /dev/null +++ b/plugins/csharp/CMakeLists.txt @@ -0,0 +1,11 @@ +# Set .NET build configuration based on CMAKE_BUILD_TYPE +if(CMAKE_BUILD_TYPE STREQUAL "Debug") + set(DOTNET_CONFIG "Debug") +else() + set(DOTNET_CONFIG "Release") +endif() + +add_subdirectory(parser) +add_subdirectory(service) + +install_webplugin(webgui) \ No newline at end of file diff --git a/plugins/csharp/migrations/20220518134047_Initial.Designer.cs b/plugins/csharp/migrations/20220518134047_Initial.Designer.cs new file mode 100644 index 000000000..0a7707b34 --- /dev/null +++ b/plugins/csharp/migrations/20220518134047_Initial.Designer.cs @@ -0,0 +1,545 @@ +// +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; + +namespace CSharpParser.Migrations +{ + [DbContext(typeof(CsharpDbContext))] + [Migration("20220518134047_Initial")] + partial class Initial + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("Relational:MaxIdentifierLength", 63) + .HasAnnotation("ProductVersion", "5.0.10") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + 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") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + 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.CsharpEnum", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + 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") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + 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") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + 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") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + 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") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + 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") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + 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") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + 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/20220518134047_Initial.cs b/plugins/csharp/migrations/20220518134047_Initial.cs new file mode 100644 index 000000000..e643a7a6a --- /dev/null +++ b/plugins/csharp/migrations/20220518134047_Initial.cs @@ -0,0 +1,443 @@ +using Microsoft.EntityFrameworkCore.Migrations; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +namespace CSharpParser.Migrations +{ + public partial class Initial : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "CsharpAstNodes", + columns: table => new + { + Id = table.Column(type: "numeric(20,0)", nullable: false), + AstValue = table.Column(type: "text", nullable: true), + AstSymbolType = table.Column(type: "integer", nullable: false), + AstType = table.Column(type: "integer", nullable: false), + Accessibility = table.Column(type: "integer", nullable: false), + Location_range_start_line = table.Column(type: "bigint", nullable: false), + Location_range_start_column = table.Column(type: "bigint", nullable: false), + Location_range_end_line = table.Column(type: "bigint", nullable: false), + Location_range_end_column = table.Column(type: "bigint", nullable: false), + Path = table.Column(type: "text", nullable: true), + EntityHash = table.Column(type: "bigint", nullable: false), + RawKind = table.Column(type: "integer", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_CsharpAstNodes", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "CsharpEtcEntitys", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + EtcEntityType = table.Column(type: "integer", nullable: false), + DeclaratorNodeId = table.Column(type: "numeric(20,0)", nullable: false), + AstNodeId = table.Column(type: "numeric(20,0)", nullable: true), + ParentNodeId = table.Column(type: "numeric(20,0)", nullable: true), + EntityHash = table.Column(type: "bigint", nullable: false), + Name = table.Column(type: "text", nullable: true), + QualifiedName = table.Column(type: "text", nullable: true), + DocumentationCommentXML = table.Column(type: "text", nullable: true), + TypeHash = table.Column(type: "bigint", nullable: false), + QualifiedType = table.Column(type: "text", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_CsharpEtcEntitys", x => x.Id); + table.ForeignKey( + name: "FK_CsharpEtcEntitys_CsharpAstNodes_AstNodeId", + column: x => x.AstNodeId, + principalTable: "CsharpAstNodes", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + table.ForeignKey( + name: "FK_CsharpEtcEntitys_CsharpAstNodes_ParentNodeId", + column: x => x.ParentNodeId, + principalTable: "CsharpAstNodes", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateTable( + name: "CsharpMethods", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + MethodType = table.Column(type: "integer", nullable: false), + AstNodeId = table.Column(type: "numeric(20,0)", nullable: true), + ParentNodeId = table.Column(type: "numeric(20,0)", nullable: true), + EntityHash = table.Column(type: "bigint", nullable: false), + Name = table.Column(type: "text", nullable: true), + QualifiedName = table.Column(type: "text", nullable: true), + DocumentationCommentXML = table.Column(type: "text", nullable: true), + TypeHash = table.Column(type: "bigint", nullable: false), + QualifiedType = table.Column(type: "text", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_CsharpMethods", x => x.Id); + table.ForeignKey( + name: "FK_CsharpMethods_CsharpAstNodes_AstNodeId", + column: x => x.AstNodeId, + principalTable: "CsharpAstNodes", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + table.ForeignKey( + name: "FK_CsharpMethods_CsharpAstNodes_ParentNodeId", + column: x => x.ParentNodeId, + principalTable: "CsharpAstNodes", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateTable( + name: "CsharpNamespaces", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + AstNodeId = table.Column(type: "numeric(20,0)", nullable: true), + ParentNodeId = table.Column(type: "numeric(20,0)", nullable: true), + EntityHash = table.Column(type: "bigint", nullable: false), + Name = table.Column(type: "text", nullable: true), + QualifiedName = table.Column(type: "text", nullable: true), + DocumentationCommentXML = table.Column(type: "text", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_CsharpNamespaces", x => x.Id); + table.ForeignKey( + name: "FK_CsharpNamespaces_CsharpAstNodes_AstNodeId", + column: x => x.AstNodeId, + principalTable: "CsharpAstNodes", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + table.ForeignKey( + name: "FK_CsharpNamespaces_CsharpAstNodes_ParentNodeId", + column: x => x.ParentNodeId, + principalTable: "CsharpAstNodes", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateTable( + name: "CsharpVariables", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + VariableType = table.Column(type: "integer", nullable: false), + AstNodeId = table.Column(type: "numeric(20,0)", nullable: true), + ParentNodeId = table.Column(type: "numeric(20,0)", nullable: true), + EntityHash = table.Column(type: "bigint", nullable: false), + Name = table.Column(type: "text", nullable: true), + QualifiedName = table.Column(type: "text", nullable: true), + DocumentationCommentXML = table.Column(type: "text", nullable: true), + TypeHash = table.Column(type: "bigint", nullable: false), + QualifiedType = table.Column(type: "text", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_CsharpVariables", x => x.Id); + table.ForeignKey( + name: "FK_CsharpVariables_CsharpAstNodes_AstNodeId", + column: x => x.AstNodeId, + principalTable: "CsharpAstNodes", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + table.ForeignKey( + name: "FK_CsharpVariables_CsharpAstNodes_ParentNodeId", + column: x => x.ParentNodeId, + principalTable: "CsharpAstNodes", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateTable( + name: "CsharpClasses", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + ClassType = table.Column(type: "integer", nullable: false), + CsharpNamespaceId = table.Column(type: "bigint", nullable: true), + AstNodeId = table.Column(type: "numeric(20,0)", nullable: true), + ParentNodeId = table.Column(type: "numeric(20,0)", nullable: true), + EntityHash = table.Column(type: "bigint", nullable: false), + Name = table.Column(type: "text", nullable: true), + QualifiedName = table.Column(type: "text", nullable: true), + DocumentationCommentXML = table.Column(type: "text", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_CsharpClasses", x => x.Id); + table.ForeignKey( + name: "FK_CsharpClasses_CsharpAstNodes_AstNodeId", + column: x => x.AstNodeId, + principalTable: "CsharpAstNodes", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + table.ForeignKey( + name: "FK_CsharpClasses_CsharpAstNodes_ParentNodeId", + column: x => x.ParentNodeId, + principalTable: "CsharpAstNodes", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + table.ForeignKey( + name: "FK_CsharpClasses_CsharpNamespaces_CsharpNamespaceId", + column: x => x.CsharpNamespaceId, + principalTable: "CsharpNamespaces", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateTable( + name: "CsharpEnums", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + CsharpNamespaceId = table.Column(type: "bigint", nullable: true), + AstNodeId = table.Column(type: "numeric(20,0)", nullable: true), + ParentNodeId = table.Column(type: "numeric(20,0)", nullable: true), + EntityHash = table.Column(type: "bigint", nullable: false), + Name = table.Column(type: "text", nullable: true), + QualifiedName = table.Column(type: "text", nullable: true), + DocumentationCommentXML = table.Column(type: "text", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_CsharpEnums", x => x.Id); + table.ForeignKey( + name: "FK_CsharpEnums_CsharpAstNodes_AstNodeId", + column: x => x.AstNodeId, + principalTable: "CsharpAstNodes", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + table.ForeignKey( + name: "FK_CsharpEnums_CsharpAstNodes_ParentNodeId", + column: x => x.ParentNodeId, + principalTable: "CsharpAstNodes", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + table.ForeignKey( + name: "FK_CsharpEnums_CsharpNamespaces_CsharpNamespaceId", + column: x => x.CsharpNamespaceId, + principalTable: "CsharpNamespaces", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateTable( + name: "CsharpStructs", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + CsharpNamespaceId = table.Column(type: "bigint", nullable: true), + AstNodeId = table.Column(type: "numeric(20,0)", nullable: true), + ParentNodeId = table.Column(type: "numeric(20,0)", nullable: true), + EntityHash = table.Column(type: "bigint", nullable: false), + Name = table.Column(type: "text", nullable: true), + QualifiedName = table.Column(type: "text", nullable: true), + DocumentationCommentXML = table.Column(type: "text", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_CsharpStructs", x => x.Id); + table.ForeignKey( + name: "FK_CsharpStructs_CsharpAstNodes_AstNodeId", + column: x => x.AstNodeId, + principalTable: "CsharpAstNodes", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + table.ForeignKey( + name: "FK_CsharpStructs_CsharpAstNodes_ParentNodeId", + column: x => x.ParentNodeId, + principalTable: "CsharpAstNodes", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + table.ForeignKey( + name: "FK_CsharpStructs_CsharpNamespaces_CsharpNamespaceId", + column: x => x.CsharpNamespaceId, + principalTable: "CsharpNamespaces", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateTable( + name: "CsharpEnumMembers", + columns: table => new + { + Id = table.Column(type: "bigint", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + EqualsValue = table.Column(type: "integer", nullable: false), + CsharpEnumId = table.Column(type: "bigint", nullable: true), + AstNodeId = table.Column(type: "numeric(20,0)", nullable: true), + ParentNodeId = table.Column(type: "numeric(20,0)", nullable: true), + EntityHash = table.Column(type: "bigint", nullable: false), + Name = table.Column(type: "text", nullable: true), + QualifiedName = table.Column(type: "text", nullable: true), + DocumentationCommentXML = table.Column(type: "text", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_CsharpEnumMembers", x => x.Id); + table.ForeignKey( + name: "FK_CsharpEnumMembers_CsharpAstNodes_AstNodeId", + column: x => x.AstNodeId, + principalTable: "CsharpAstNodes", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + table.ForeignKey( + name: "FK_CsharpEnumMembers_CsharpAstNodes_ParentNodeId", + column: x => x.ParentNodeId, + principalTable: "CsharpAstNodes", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + table.ForeignKey( + name: "FK_CsharpEnumMembers_CsharpEnums_CsharpEnumId", + column: x => x.CsharpEnumId, + principalTable: "CsharpEnums", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateIndex( + name: "IX_CsharpClasses_AstNodeId", + table: "CsharpClasses", + column: "AstNodeId"); + + migrationBuilder.CreateIndex( + name: "IX_CsharpClasses_CsharpNamespaceId", + table: "CsharpClasses", + column: "CsharpNamespaceId"); + + migrationBuilder.CreateIndex( + name: "IX_CsharpClasses_ParentNodeId", + table: "CsharpClasses", + column: "ParentNodeId"); + + migrationBuilder.CreateIndex( + name: "IX_CsharpEnumMembers_AstNodeId", + table: "CsharpEnumMembers", + column: "AstNodeId"); + + migrationBuilder.CreateIndex( + name: "IX_CsharpEnumMembers_CsharpEnumId", + table: "CsharpEnumMembers", + column: "CsharpEnumId"); + + migrationBuilder.CreateIndex( + name: "IX_CsharpEnumMembers_ParentNodeId", + table: "CsharpEnumMembers", + column: "ParentNodeId"); + + migrationBuilder.CreateIndex( + name: "IX_CsharpEnums_AstNodeId", + table: "CsharpEnums", + column: "AstNodeId"); + + migrationBuilder.CreateIndex( + name: "IX_CsharpEnums_CsharpNamespaceId", + table: "CsharpEnums", + column: "CsharpNamespaceId"); + + migrationBuilder.CreateIndex( + name: "IX_CsharpEnums_ParentNodeId", + table: "CsharpEnums", + column: "ParentNodeId"); + + migrationBuilder.CreateIndex( + name: "IX_CsharpEtcEntitys_AstNodeId", + table: "CsharpEtcEntitys", + column: "AstNodeId"); + + migrationBuilder.CreateIndex( + name: "IX_CsharpEtcEntitys_ParentNodeId", + table: "CsharpEtcEntitys", + column: "ParentNodeId"); + + migrationBuilder.CreateIndex( + name: "IX_CsharpMethods_AstNodeId", + table: "CsharpMethods", + column: "AstNodeId"); + + migrationBuilder.CreateIndex( + name: "IX_CsharpMethods_ParentNodeId", + table: "CsharpMethods", + column: "ParentNodeId"); + + migrationBuilder.CreateIndex( + name: "IX_CsharpNamespaces_AstNodeId", + table: "CsharpNamespaces", + column: "AstNodeId"); + + migrationBuilder.CreateIndex( + name: "IX_CsharpNamespaces_ParentNodeId", + table: "CsharpNamespaces", + column: "ParentNodeId"); + + migrationBuilder.CreateIndex( + name: "IX_CsharpStructs_AstNodeId", + table: "CsharpStructs", + column: "AstNodeId"); + + migrationBuilder.CreateIndex( + name: "IX_CsharpStructs_CsharpNamespaceId", + table: "CsharpStructs", + column: "CsharpNamespaceId"); + + migrationBuilder.CreateIndex( + name: "IX_CsharpStructs_ParentNodeId", + table: "CsharpStructs", + column: "ParentNodeId"); + + migrationBuilder.CreateIndex( + name: "IX_CsharpVariables_AstNodeId", + table: "CsharpVariables", + column: "AstNodeId"); + + migrationBuilder.CreateIndex( + name: "IX_CsharpVariables_ParentNodeId", + table: "CsharpVariables", + column: "ParentNodeId"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "CsharpClasses"); + + migrationBuilder.DropTable( + name: "CsharpEnumMembers"); + + migrationBuilder.DropTable( + name: "CsharpEtcEntitys"); + + migrationBuilder.DropTable( + name: "CsharpMethods"); + + migrationBuilder.DropTable( + name: "CsharpStructs"); + + migrationBuilder.DropTable( + name: "CsharpVariables"); + + migrationBuilder.DropTable( + name: "CsharpEnums"); + + migrationBuilder.DropTable( + name: "CsharpNamespaces"); + + migrationBuilder.DropTable( + name: "CsharpAstNodes"); + } + } +} diff --git a/plugins/csharp/migrations/CsharpDbContextModelSnapshot.cs b/plugins/csharp/migrations/CsharpDbContextModelSnapshot.cs new file mode 100644 index 000000000..20ebbc516 --- /dev/null +++ b/plugins/csharp/migrations/CsharpDbContextModelSnapshot.cs @@ -0,0 +1,543 @@ +// +using System; +using CSharpParser.model; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +namespace CSharpParser.Migrations +{ + [DbContext(typeof(CsharpDbContext))] + partial class CsharpDbContextModelSnapshot : ModelSnapshot + { + 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); + + 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") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + 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.CsharpEnum", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + 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") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + 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") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + 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") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + 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") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + 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") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + 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") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + 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/model/CsharpAstNode.cs b/plugins/csharp/model/CsharpAstNode.cs new file mode 100644 index 000000000..182a2160e --- /dev/null +++ b/plugins/csharp/model/CsharpAstNode.cs @@ -0,0 +1,68 @@ +using System.ComponentModel.DataAnnotations.Schema; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; + +namespace CSharpParser.model +{ + enum AstSymbolTypeEnum + { + Variable, + Method, + Class, + Struct, + Namespace, + Enum, + EnumMember, + EtcEntity + + } + + enum AstTypeEnum + { + Declaration, + Definition, + Usage, + Read, + Write, + Expression + } + + class CsharpAstNode + { + public ulong Id { get; set; } + public string AstValue { get; set; } + public AstSymbolTypeEnum AstSymbolType { get; set; } + public AstTypeEnum AstType { get; set; } + public Accessibility Accessibility { get; set; } + public long Location_range_start_line { get; set; } + public long Location_range_start_column { get; set; } + public long Location_range_end_line { get; set; } + public long Location_range_end_column { get; set; } + public string Path { get; set; } + public long EntityHash { get; set; } + public SyntaxKind RawKind { get; set; } //SyntaxKind Enum + public void SetLocation(FileLinePositionSpan f) + { + Location_range_start_line = f.StartLinePosition.Line+1; + Location_range_start_column = f.StartLinePosition.Character+1; + Location_range_end_line = f.EndLinePosition.Line+1; + Location_range_end_column = f.EndLinePosition.Character+1; + Path = f.Path; + } + public bool isRangeSmaller(CsharpAstNode other){ + if (Location_range_start_line == other.Location_range_start_line){ + if (Location_range_end_line == other.Location_range_end_line){ + return Location_range_end_column - Location_range_start_column < + other.Location_range_end_column - other.Location_range_start_column; + } + return Location_range_end_line < other.Location_range_end_line; + } else if (Location_range_end_line - Location_range_start_line == + other.Location_range_end_line - other.Location_range_start_line){ + return Location_range_end_column - Location_range_start_column < + other.Location_range_end_column - other.Location_range_start_column; + } + return Location_range_end_line - Location_range_start_line < + other.Location_range_end_line - other.Location_range_start_line; + } + } +} diff --git a/plugins/csharp/model/CsharpClass.cs b/plugins/csharp/model/CsharpClass.cs new file mode 100644 index 000000000..fa6642923 --- /dev/null +++ b/plugins/csharp/model/CsharpClass.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; + +namespace CSharpParser.model +{ + enum ClassTypeEnum + { + Class, + Interface, + Record + } + class CsharpClass : CsharpEntity + { + public ClassTypeEnum ClassType { get; set; } + public CsharpNamespace CsharpNamespace { get; set; } + } + //[Table("csharp_structs")] + class CsharpStruct : CsharpEntity + { + public CsharpNamespace CsharpNamespace { get; set; } + } +} diff --git a/plugins/csharp/model/CsharpDbContext.cs b/plugins/csharp/model/CsharpDbContext.cs new file mode 100644 index 000000000..eaef779d1 --- /dev/null +++ b/plugins/csharp/model/CsharpDbContext.cs @@ -0,0 +1,23 @@ +using System.Text; +using Microsoft.EntityFrameworkCore; + +namespace CSharpParser.model +{ + class CsharpDbContext : DbContext + { + public CsharpDbContext(DbContextOptions options) : base(options) { } + + public DbSet CsharpAstNodes { get; set; } + public DbSet CsharpNamespaces { get; set; } + public DbSet CsharpClasses { get; set; } + public DbSet CsharpMethods { get; set; } + public DbSet CsharpVariables { get; set; } + public DbSet CsharpStructs { get; set; } + public DbSet CsharpEnums { get; set; } + public DbSet CsharpEnumMembers { get; set; } + public DbSet CsharpEtcEntitys { get; set; } + + + } + +} diff --git a/plugins/csharp/model/CsharpEntity.cs b/plugins/csharp/model/CsharpEntity.cs new file mode 100644 index 000000000..c7c85b7c7 --- /dev/null +++ b/plugins/csharp/model/CsharpEntity.cs @@ -0,0 +1,33 @@ +using System; + +namespace CSharpParser.model +{ + class CsharpEntity + { + public long Id { get; set; } + public CsharpAstNode AstNode { get; set; } + public CsharpAstNode ParentNode{ get; set; } + public long EntityHash { get; set; } + public String Name { get; set; } = " "; + public String QualifiedName { get; set; } = " "; + public string DocumentationCommentXML { get; set; } = " "; + } + + class CsharpTypedEntity : CsharpEntity + { + public long TypeHash { get; set; } + public String QualifiedType { get; set; } = " "; + } + + enum EtcEntityTypeEnum + { + Event, + Invocation, + ForeachExpr + } + class CsharpEtcEntity : CsharpTypedEntity + { + public EtcEntityTypeEnum EtcEntityType { get; set; } + public ulong DeclaratorNodeId { get; set; } + } +} diff --git a/plugins/csharp/model/CsharpEnum.cs b/plugins/csharp/model/CsharpEnum.cs new file mode 100644 index 000000000..5597d05d8 --- /dev/null +++ b/plugins/csharp/model/CsharpEnum.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; + +namespace CSharpParser.model +{ + //[Table("csharp_enums")] + class CsharpEnum : CsharpEntity + { + public CsharpNamespace CsharpNamespace { get; set; } + public HashSet CsharpEnumMembers { get; set; } = new HashSet(); + + public void AddMember(CsharpEnumMember member) + { + CsharpEnumMembers.Add(member); + } + } +} diff --git a/plugins/csharp/model/CsharpEnumMember.cs b/plugins/csharp/model/CsharpEnumMember.cs new file mode 100644 index 000000000..835147ea1 --- /dev/null +++ b/plugins/csharp/model/CsharpEnumMember.cs @@ -0,0 +1,10 @@ +using System.ComponentModel.DataAnnotations.Schema; + +namespace CSharpParser.model +{ + //[Table("csharp_enum_members")] + class CsharpEnumMember : CsharpEntity + { + public int EqualsValue { get; set; } + } +} diff --git a/plugins/csharp/model/CsharpMethod.cs b/plugins/csharp/model/CsharpMethod.cs new file mode 100644 index 000000000..087053af3 --- /dev/null +++ b/plugins/csharp/model/CsharpMethod.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; + +namespace CSharpParser.model +{ + enum MethodTypeEnum + { + Delegate, + Accessor, + Constructor, + Destuctor, + Method, + Operator + } + + class CsharpMethod : CsharpTypedEntity + { + public MethodTypeEnum MethodType { get; set; } + } + +} diff --git a/plugins/csharp/model/CsharpNamespace.cs b/plugins/csharp/model/CsharpNamespace.cs new file mode 100644 index 000000000..8b4cdc4fd --- /dev/null +++ b/plugins/csharp/model/CsharpNamespace.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; + +namespace CSharpParser.model +{ + //[Table("csharp_namespaces")] + class CsharpNamespace : CsharpEntity + { + + } +} diff --git a/plugins/csharp/model/CsharpVariable.cs b/plugins/csharp/model/CsharpVariable.cs new file mode 100644 index 000000000..9b3a7b1e3 --- /dev/null +++ b/plugins/csharp/model/CsharpVariable.cs @@ -0,0 +1,17 @@ +using System.ComponentModel.DataAnnotations.Schema; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace CSharpParser.model +{ + enum VariableTypeEnum + { + Property, + LINQ, + Parameter, + Variable + } + class CsharpVariable : CsharpTypedEntity + { + public VariableTypeEnum VariableType { get; set; } + } +} diff --git a/plugins/csharp/parser/CMakeLists.txt b/plugins/csharp/parser/CMakeLists.txt new file mode 100644 index 000000000..7293d9c0c --- /dev/null +++ b/plugins/csharp/parser/CMakeLists.txt @@ -0,0 +1,18 @@ +add_subdirectory(src_csharp) + +include_directories( + include + ${PROJECT_SOURCE_DIR}/model/include + ${PROJECT_SOURCE_DIR}/util/include + ${PROJECT_SOURCE_DIR}/parser/include + ${CMAKE_BINARY_DIR}/model/include) + +add_library(csharpparser SHARED + src/csharpparser.cpp) + +target_link_libraries(csharpparser + model) + +target_compile_options(csharpparser PUBLIC -Wno-unknown-pragmas) + +install(TARGETS csharpparser DESTINATION ${INSTALL_PARSER_DIR}) diff --git a/plugins/csharp/parser/include/csharpparser/csharpparser.h b/plugins/csharp/parser/include/csharpparser/csharpparser.h new file mode 100644 index 000000000..6435dcf53 --- /dev/null +++ b/plugins/csharp/parser/include/csharpparser/csharpparser.h @@ -0,0 +1,43 @@ +#ifndef CC_PARSER_CSHARPPARSER_H +#define CC_PARSER_CSHARPPARSER_H + +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace cc +{ +namespace parser +{ + +namespace fs = boost::filesystem; +namespace bp = boost::process; +namespace pt = boost::property_tree; + +class CsharpParser : public AbstractParser +{ +public: + CsharpParser(ParserContext& ctx_); + virtual ~CsharpParser(); + virtual bool parse() override; +private: + int _numCompileCommands; + int _threadNum; + + bool acceptProjectBuildPath(const std::string& buildDir_); + bool parseProjectBuildPath( + const std::vector& path_, + const std::string& buildPath_); + void addSource(const std::string& filepath_, bool error_); +}; + +} // parser +} // cc + +#endif // CC_PLUGINS_PARSER_DUMMYPARSER_H diff --git a/plugins/csharp/parser/src/csharpparser.cpp b/plugins/csharp/parser/src/csharpparser.cpp new file mode 100644 index 000000000..490c82f56 --- /dev/null +++ b/plugins/csharp/parser/src/csharpparser.cpp @@ -0,0 +1,194 @@ +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include + +namespace cc +{ +namespace parser +{ + +CsharpParser::CsharpParser(ParserContext& ctx_): AbstractParser(ctx_) +{ + _threadNum = _ctx.options["jobs"].as(); +} +/* +bool CsharpParser::acceptProjectBuildPath(const std::vector& path_) +{ + return path_.size() >= 2 && fs::is_directory(path_[0]) && fs::is_directory(path_[1]); +}*/ +bool CsharpParser::acceptProjectBuildPath(const std::string& buildPath_) +{ + return fs::is_directory(buildPath_); +} + +bool CsharpParser::parse() +{ + bool success = true; + + std::vector paths = _ctx.options["input"].as>(); + std::string buildPath = _ctx.options["build-dir"].as(); + + if (acceptProjectBuildPath(buildPath)) + { + LOG(debug) << "C# parser parse path: " << paths[0]; + LOG(debug) << "Parsed csharp project build path: " << buildPath; + success = success && parseProjectBuildPath(paths, buildPath); + } + else + { + LOG(error) << "Build path must be a directory!"; + success = false; + } + + return success; +} + +bool CsharpParser::parseProjectBuildPath( + const std::vector& paths_, + const std::string& buildPath_) +{ + namespace ch = std::chrono; + std::future log; + fs::path csharp_path = util::findCurrentExecutableDir() + "/../lib/csharp/"; + + /* + * Concatenate the command parameters to pass to the C# parser. + * 1) C# parser binary + * 2) Database connection string + * 3) Project build directory path + * 4) CC lib directory path + * 5) Thread number + * 6+) Source directories + */ + std::string command("./CSharpParser "); + command.append("'"); + command.append(_ctx.options["database"].as()); + command.append("' '"); + command.append(buildPath_); + command.append("' '"); + command.append(csharp_path.string()); + command.append("' "); + command.append(std::to_string(_ctx.options["jobs"].as())); + + for (auto p : paths_) + { + if (fs::is_directory(p)) + { + command.append(" '"); + command.append(p); + command.append("' "); + } + } + + LOG(debug) << "CSharpParser command: " << command; + + ch::steady_clock::time_point begin = ch::steady_clock::now(); + + int result = bp::system(command, bp::start_dir(csharp_path), bp::std_out > log); + + ch::steady_clock::time_point current = ch::steady_clock::now(); + float elapsed_time = ch::duration_cast(current - begin).count(); + LOG(debug) << "CSharp Parse time: " << elapsed_time << " ms"; + + 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')) + { + if (line[0] == '+' || line[0] == '-') + { + addSource(line.substr(1), line[0] == '-'); + if (line[0] == '+') + { + countFull++; + } + else + { + countPart++; + } + } + } + + ch::steady_clock::time_point after = ch::steady_clock::now(); + elapsed_time = + ch::duration_cast(after - current).count(); + + LOG(debug) << "C# source manage time: " << elapsed_time << " ms"; + LOG(info) << "Number of files fully parsed: " << countFull << + ", partially parsed: " << countPart << ", total: " << countFull+countPart; + + return result == 0; +} + +void CsharpParser::addSource(const std::string& filepath_, bool error_) +{ + util::OdbTransaction transaction(_ctx.db); + + model::BuildActionPtr buildAction(new model::BuildAction); + buildAction->command = " "; + buildAction->type = model::BuildAction::Compile; + + model::BuildSource buildSource; + buildSource.file = _ctx.srcMgr.getFile(filepath_); + buildSource.file->parseStatus = error_ + ? model::File::PSPartiallyParsed + : model::File::PSFullyParsed; + buildSource.file->type = "CS"; + buildSource.action = buildAction; + + _ctx.srcMgr.updateFile(*buildSource.file); + _ctx.srcMgr.persistFiles(); + + transaction([&, this] { + _ctx.db->persist(buildAction); + _ctx.db->persist(buildSource); + }); +} + + +CsharpParser::~CsharpParser() +{ +} + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wreturn-type-c-linkage" +extern "C" +{ + boost::program_options::options_description getOptions() + { + boost::program_options::options_description description("C# Plugin"); + + description.add_options() + ("build-dir,b", po::value()->default_value("Build directory"), + "The build directory of the parsed project."); + + return description; + } + + std::shared_ptr make(ParserContext& ctx_) + { + return std::make_shared(ctx_); + } +} +#pragma clang diagnostic pop + +} // parser +} // cc diff --git a/plugins/csharp/parser/src_csharp/AstVisitor.cs b/plugins/csharp/parser/src_csharp/AstVisitor.cs new file mode 100644 index 000000000..722804bf9 --- /dev/null +++ b/plugins/csharp/parser/src_csharp/AstVisitor.cs @@ -0,0 +1,1007 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using static System.Console; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using CSharpParser.model; +using Microsoft.CodeAnalysis; + +namespace CSharpParser +{ + partial class AstVisitor : CSharpSyntaxWalker + { + private readonly CsharpDbContext DbContext; + private readonly SemanticModel Model; + private readonly SyntaxTree Tree; + + public bool FullyParsed = true; + + public AstVisitor(CsharpDbContext context, SemanticModel model, SyntaxTree tree) + { + this.DbContext = context; + this.Model = model; + this.Tree = tree; + } + + private ulong createIdentifier(CsharpAstNode astNode){ + string[] properties = + { + astNode.AstValue,":", + astNode.AstType.ToString(),":", + astNode.EntityHash.ToString(),":", + astNode.RawKind.ToString(),":", + astNode.Path,":", + astNode.Location_range_start_line.ToString(),":", + astNode.Location_range_start_column.ToString(),":", + astNode.Location_range_end_line.ToString(),":", + astNode.Location_range_end_column.ToString() + }; + + string res = string.Concat(properties); + + //WriteLine(res); + return fnvHash(res); + } + + 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 ulong getAstNodeId(SyntaxNode node){ + CsharpAstNode astNode = new CsharpAstNode + { + AstValue = node.ToString(), + RawKind = node.Kind(), + EntityHash = node.GetHashCode(), + AstType = AstTypeEnum.Declaration + }; + astNode.SetLocation(node.SyntaxTree.GetLineSpan(node.Span)); + var ret = createIdentifier(astNode); + return ret; + } + + private CsharpAstNode AstNode(SyntaxNode node, AstSymbolTypeEnum type, AstTypeEnum astType) + { + Accessibility acc = Accessibility.NotApplicable; + try + { + acc = Model.GetDeclaredSymbol(node).DeclaredAccessibility; + } + catch (Exception) + { + //WriteLine($"Can not get GetDeclaredSymbol of this node: {node}"); + } + CsharpAstNode astNode = new CsharpAstNode + { + AstValue = node.ToString(), + RawKind = node.Kind(), + EntityHash = node.GetHashCode(), + AstSymbolType = type, + AstType = astType, + Accessibility = acc + }; + astNode.SetLocation(Tree.GetLineSpan(node.Span)); + astNode.Id = createIdentifier(astNode); + + if (DbContext.CsharpAstNodes.Find(astNode.Id) == null) + { + DbContext.CsharpAstNodes.Add(astNode); + } + return astNode; + } + + private CsharpAstNode AstNode(SyntaxNode node, AstSymbolTypeEnum type) + { + return AstNode(node, type, AstTypeEnum.Declaration); + } + + public override void VisitUsingDirective(UsingDirectiveSyntax node) + { + base.VisitUsingDirective(node); + } + + public override void VisitNamespaceDeclaration(NamespaceDeclarationSyntax node) + { + CsharpAstNode astNode = AstNode(node, AstSymbolTypeEnum.Namespace); + string qName = ""; + try + { + qName = Model.GetDeclaredSymbol(node).ToString(); + } + catch (Exception) + { + FullyParsed = false; + } + + CsharpNamespace csharpNamespace = new CsharpNamespace + { + AstNode = astNode, + Name = node.Name.ToString(), + QualifiedName = qName, + DocumentationCommentXML = Model.GetDeclaredSymbol(node).GetDocumentationCommentXml(), + EntityHash = astNode.EntityHash + }; + + var nameSpaces = DbContext.CsharpNamespaces.Where(n => n.Name == csharpNamespace.Name).ToList(); + if (nameSpaces.Count == 0) + { + DbContext.CsharpNamespaces.Add(csharpNamespace); + } + + base.VisitNamespaceDeclaration(node); + } + + public override void VisitInterfaceDeclaration(InterfaceDeclarationSyntax node) + { + CsharpAstNode astNode = AstNode(node, AstSymbolTypeEnum.Class); + base.VisitInterfaceDeclaration(node); + string qName = ""; + try + { + qName = Model.GetDeclaredSymbol(node).ToString(); + } + catch (Exception) + { + FullyParsed = false; + //WriteLine($"Can not get QualifiedName of this name: {node.Identifier}"); + } + + var nameSpaces = DbContext.CsharpNamespaces.Where(n => qName.Contains(n.Name)).ToList(); + CsharpNamespace csharpNamespace = null; + if (nameSpaces.Count != 0) + { + csharpNamespace = nameSpaces.First(); + } + + CsharpClass csharpClass = new CsharpClass + { + ClassType = ClassTypeEnum.Interface, + CsharpNamespace = csharpNamespace, + AstNode = astNode, + Name = node.Identifier.Text, + QualifiedName = qName, + DocumentationCommentXML = Model.GetDeclaredSymbol(node).GetDocumentationCommentXml(), + EntityHash = astNode.EntityHash + }; + + foreach (PropertyDeclarationSyntax propertyDeclaration in node.Members.OfType()) + { + VisitPropertyDecl(propertyDeclaration, astNode); + } + + foreach (MethodDeclarationSyntax methodDeclaration in node.Members.OfType()) + { + VisitMethodDecl(methodDeclaration, astNode); + } + + foreach (OperatorDeclarationSyntax operatorDeclaration in node.Members.OfType()) + { + VisitOperatorDecl(operatorDeclaration, astNode); + } + + DbContext.CsharpClasses.Add(csharpClass); + } + + public override void VisitStructDeclaration(StructDeclarationSyntax node) + { + CsharpAstNode astNode = AstNode(node, AstSymbolTypeEnum.Struct); + base.VisitStructDeclaration(node); + string qName = ""; + try + { + qName = Model.GetDeclaredSymbol(node).ToString(); + } + catch (Exception) + { + FullyParsed = false; + } + + var nameSpaces = DbContext.CsharpNamespaces.Where(n => qName.Contains(n.Name)).ToList(); + CsharpNamespace csharpNamespace = null; + if (nameSpaces.Count != 0) + { + csharpNamespace = nameSpaces.First(); + } + + CsharpStruct csharpStruct = new CsharpStruct + { + CsharpNamespace = csharpNamespace, + AstNode = astNode, + Name = node.Identifier.Text, + QualifiedName = qName, + DocumentationCommentXML = Model.GetDeclaredSymbol(node).GetDocumentationCommentXml(), + EntityHash = astNode.EntityHash + }; + + foreach (VariableDeclarationSyntax variableDeclaration in node.Members.OfType()) + { + VisitVariableDecl(variableDeclaration, astNode); + } + + foreach (PropertyDeclarationSyntax propertyDeclaration in node.Members.OfType()) + { + VisitPropertyDecl(propertyDeclaration, astNode); + VisitAccessors(propertyDeclaration.AccessorList, propertyDeclaration.Identifier.Text, astNode); + } + + foreach (MethodDeclarationSyntax methodDeclaration in node.Members.OfType()) + { + VisitMethodDecl(methodDeclaration, astNode); + } + + foreach (OperatorDeclarationSyntax operatorDeclaration in node.Members.OfType()) + { + VisitOperatorDecl(operatorDeclaration, astNode); + } + + foreach (DelegateDeclarationSyntax delegateDeclaration in node.Members.OfType()) + { + VisitDelegateDecl(delegateDeclaration, astNode); + } + + foreach (ConstructorDeclarationSyntax constructorDeclaration in node.Members.OfType()) + { + VisitConstructorDecl(constructorDeclaration, astNode); + } + + foreach (DestructorDeclarationSyntax destructorDeclaration in node.Members.OfType()) + { + VisitDestructorDecl(destructorDeclaration, astNode); + } + + foreach (EventDeclarationSyntax eventDeclaration in node.Members.OfType()) + { + CsharpAstNode astNode2 = AstNode(eventDeclaration, AstSymbolTypeEnum.EtcEntity); + string qName2 = ""; + try + { + qName2 = Model.GetDeclaredSymbol(node).ToString(); + } + catch (Exception) + { + //WriteLine($"Can not get QualifiedName of this name: {node.Identifier}"); + } + CsharpEtcEntity csharpEntity = new CsharpEtcEntity + { + AstNode = astNode2, + Name = eventDeclaration.Identifier.Text, + QualifiedName = qName, + DocumentationCommentXML = Model.GetDeclaredSymbol(eventDeclaration).GetDocumentationCommentXml(), + EntityHash = astNode.EntityHash, + ParentNode = astNode, + EtcEntityType = EtcEntityTypeEnum.Event + }; + DbContext.CsharpEtcEntitys.Add(csharpEntity); + } + + DbContext.CsharpStructs.Add(csharpStruct); + } + + public override void VisitClassDeclaration(ClassDeclarationSyntax node) + { + CsharpAstNode astNode = AstNode(node, AstSymbolTypeEnum.Class); + base.VisitClassDeclaration(node); + string qName = ""; + try + { + qName = Model.GetDeclaredSymbol(node).ToString(); + } + catch (Exception) + { + FullyParsed = false; + } + + var nameSpaces = DbContext.CsharpNamespaces.Where(n => qName.Contains(n.Name)).ToList(); + CsharpNamespace csharpNamespace = null; + if (nameSpaces.Count != 0) + { + csharpNamespace = nameSpaces.First(); + } + + CsharpClass csharpClass = new CsharpClass + { + CsharpNamespace = csharpNamespace, + AstNode = astNode, + Name = node.Identifier.Text, + QualifiedName = qName, + DocumentationCommentXML = Model.GetDeclaredSymbol(node).GetDocumentationCommentXml(), + EntityHash = astNode.EntityHash + }; + + foreach (var variableDeclaration in node.Members.OfType()) + { + VisitVariableDecl(variableDeclaration.Declaration, astNode); + } + + foreach (PropertyDeclarationSyntax propertyDeclaration in node.Members.OfType()) + { + VisitPropertyDecl(propertyDeclaration, astNode); + VisitAccessors(propertyDeclaration.AccessorList, propertyDeclaration.Identifier.Text, astNode); + } + + foreach (MethodDeclarationSyntax methodDeclaration in node.Members.OfType()) + { + VisitMethodDecl(methodDeclaration, astNode); + } + + foreach (OperatorDeclarationSyntax operatorDeclaration in node.Members.OfType()) + { + VisitOperatorDecl(operatorDeclaration, astNode); + } + + foreach (DelegateDeclarationSyntax delegateDeclaration in node.Members.OfType()) + { + VisitDelegateDecl(delegateDeclaration, astNode); + } + + foreach (ConstructorDeclarationSyntax constructorDeclaration in node.Members.OfType()) + { + VisitConstructorDecl(constructorDeclaration, astNode); + } + + foreach (DestructorDeclarationSyntax destructorDeclaration in node.Members.OfType()) + { + VisitDestructorDecl(destructorDeclaration,astNode); + } + + foreach (EventDeclarationSyntax eventDeclaration in node.Members.OfType()) + { + CsharpAstNode astNode2 = AstNode(eventDeclaration,AstSymbolTypeEnum.EtcEntity); + string qName2 = ""; + try + { + qName2 = Model.GetDeclaredSymbol(node).ToString(); + } + catch (Exception) + { + //WriteLine($"Can not get QualifiedName of this name: {node.Identifier}"); + } + CsharpEtcEntity csharpEntity = new CsharpEtcEntity + { + AstNode = astNode2, + EtcEntityType = EtcEntityTypeEnum.Event, + Name = eventDeclaration.Identifier.Text, + QualifiedName = qName, + DocumentationCommentXML = Model.GetDeclaredSymbol(eventDeclaration).GetDocumentationCommentXml(), + EntityHash = astNode.EntityHash, + ParentNode = astNode + }; + DbContext.CsharpEtcEntitys.Add(csharpEntity); + } + + DbContext.CsharpClasses.Add(csharpClass); + } + + public override void VisitRecordDeclaration(RecordDeclarationSyntax node) { + CsharpAstNode astNode = AstNode(node, AstSymbolTypeEnum.Class); + base.VisitRecordDeclaration(node); + string qName = ""; + try + { + qName = Model.GetDeclaredSymbol(node).ToString(); + } + catch (Exception) + { + FullyParsed = false; + } + + var nameSpaces = DbContext.CsharpNamespaces.Where(n => qName.Contains(n.Name)).ToList(); + CsharpNamespace csharpNamespace = null; + if (nameSpaces.Count == 1) + { + csharpNamespace = nameSpaces.First(); + } + + CsharpClass csharpRecord = new CsharpClass + { + ClassType = ClassTypeEnum.Record, + CsharpNamespace = csharpNamespace, + AstNode = astNode, + Name = node.Identifier.Text, + QualifiedName = qName, + DocumentationCommentXML = Model.GetDeclaredSymbol(node).GetDocumentationCommentXml(), + EntityHash = astNode.EntityHash + }; + + foreach (var variableDeclaration in node.Members.OfType()) + { + VisitVariableDecl(variableDeclaration.Declaration, astNode); + } + + foreach (PropertyDeclarationSyntax propertyDeclaration in node.Members.OfType()) + { + VisitPropertyDecl(propertyDeclaration, astNode); + VisitAccessors(propertyDeclaration.AccessorList, propertyDeclaration.Identifier.Text, astNode); + } + + foreach (MethodDeclarationSyntax methodDeclaration in node.Members.OfType()) + { + VisitMethodDecl(methodDeclaration, astNode); + } + + foreach (OperatorDeclarationSyntax operatorDeclaration in node.Members.OfType()) + { + VisitOperatorDecl(operatorDeclaration, astNode); + } + + foreach (DelegateDeclarationSyntax delegateDeclaration in node.Members.OfType()) + { + VisitDelegateDecl(delegateDeclaration, astNode); + } + + foreach (ConstructorDeclarationSyntax constructorDeclaration in node.Members.OfType()) + { + VisitConstructorDecl(constructorDeclaration, astNode); + } + + foreach (DestructorDeclarationSyntax destructorDeclaration in node.Members.OfType()) + { + VisitDestructorDecl(destructorDeclaration, astNode); + } + + foreach (EventDeclarationSyntax eventDeclaration in node.Members.OfType()) + { + CsharpAstNode astNode2 = AstNode(eventDeclaration, AstSymbolTypeEnum.EtcEntity); + string qName2 = ""; + try + { + qName2 = Model.GetDeclaredSymbol(node).ToString(); + } + catch (Exception) + { + //WriteLine($"Can not get QualifiedName of this name: {node.Identifier}"); + } + CsharpEtcEntity csharpEntity = new CsharpEtcEntity + { + AstNode = astNode2, + EtcEntityType = EtcEntityTypeEnum.Event, + Name = eventDeclaration.Identifier.Text, + QualifiedName = qName, + DocumentationCommentXML = Model.GetDeclaredSymbol(eventDeclaration).GetDocumentationCommentXml(), + EntityHash = astNode.EntityHash, + ParentNode = astNode + }; + DbContext.CsharpEtcEntitys.Add(csharpEntity); + } + + DbContext.CsharpClasses.Add(csharpRecord); + } + + private void VisitDelegateDecl(DelegateDeclarationSyntax node, CsharpAstNode parent) + { + CsharpAstNode astNode = AstNode(node,AstSymbolTypeEnum.Method); + string qName = ""; + try + { + qName = Model.GetDeclaredSymbol(node).ToString(); + } + catch (Exception) + { + FullyParsed = false; + } + + CsharpMethod method = new CsharpMethod + { + AstNode = astNode, + Name = node.Identifier.Text, + QualifiedName = qName, + DocumentationCommentXML = Model.GetDeclaredSymbol(node).GetDocumentationCommentXml(), + EntityHash = astNode.EntityHash, + ParentNode = parent, + MethodType = MethodTypeEnum.Delegate + }; + + if (node.ParameterList.Parameters.Count > 0) + { + VisitMethodParameters(node.ParameterList.Parameters, astNode); + } + + DbContext.CsharpMethods.Add(method); + } + + private void VisitDestructorDecl(DestructorDeclarationSyntax node, CsharpAstNode parent) + { + CsharpAstNode astNode = AstNode(node, AstSymbolTypeEnum.Method); + string qName = ""; + try + { + qName = Model.GetDeclaredSymbol(node).ToString(); + } + catch (Exception) + { + FullyParsed = false; + } + + CsharpMethod method = new CsharpMethod + { + AstNode = astNode, + Name = node.Identifier.Text, + QualifiedName = qName, + DocumentationCommentXML = Model.GetDeclaredSymbol(node).GetDocumentationCommentXml(), + EntityHash = astNode.EntityHash, + ParentNode = parent, + MethodType = MethodTypeEnum.Destuctor + }; + + if (node.ParameterList.Parameters.Count > 0) + { + VisitMethodParameters(node.ParameterList.Parameters,astNode); + } + + foreach (VariableDeclarationSyntax variableDeclaration in node.DescendantNodes().OfType()) + { + VisitVariableDecl(variableDeclaration, astNode); + } + + DbContext.CsharpMethods.Add(method); + } + + private void VisitConstructorDecl(ConstructorDeclarationSyntax node, CsharpAstNode parent) + { + CsharpAstNode astNode = AstNode(node, AstSymbolTypeEnum.Method); + string qName = ""; + try + { + qName = Model.GetDeclaredSymbol(node).ToString(); + } + catch (Exception) + { + FullyParsed = false; + } + + CsharpMethod method = new CsharpMethod + { + AstNode = astNode, + Name = node.Identifier.Text, + QualifiedName = qName, + DocumentationCommentXML = Model.GetDeclaredSymbol(node).GetDocumentationCommentXml(), + EntityHash = astNode.EntityHash, + ParentNode = parent, + MethodType = MethodTypeEnum.Constructor + }; + + if (node.ParameterList.Parameters.Count > 0) + { + VisitMethodParameters(node.ParameterList.Parameters,astNode); + } + + foreach (VariableDeclarationSyntax variableDeclaration in node.DescendantNodes().OfType()) + { + VisitVariableDecl(variableDeclaration, astNode); + } + + DbContext.CsharpMethods.Add(method); + } + + private void VisitMethodDecl(MethodDeclarationSyntax node, CsharpAstNode parent) + { + CsharpAstNode astNode = AstNode(node, AstSymbolTypeEnum.Method); + string qName = ""; + try + { + qName = Model.GetDeclaredSymbol(node).ToString(); + } + catch (Exception) + { + FullyParsed = false; + } + + string qType = ""; + try + { + qType = Model.GetSymbolInfo(node.ReturnType).Symbol.ToString(); + } + catch (Exception) + { + FullyParsed = false; + } + + CsharpMethod method = new CsharpMethod + { + AstNode = astNode, + Name = node.Identifier.Text, + QualifiedName = qName, + QualifiedType = qType, + DocumentationCommentXML = Model.GetDeclaredSymbol(node).GetDocumentationCommentXml(), + TypeHash = qType.GetHashCode(), + EntityHash = astNode.EntityHash, + ParentNode = parent, + MethodType = MethodTypeEnum.Method + }; + + if (node.ParameterList.Parameters.Count > 0) + { + VisitMethodParameters(node.ParameterList.Parameters,astNode); + } + + foreach (VariableDeclarationSyntax variableDeclaration in node.DescendantNodes().OfType()) + { + VisitVariableDecl(variableDeclaration, astNode); + } + + DbContext.CsharpMethods.Add(method); + } + + private void VisitOperatorDecl(OperatorDeclarationSyntax node, CsharpAstNode parent) + { + CsharpAstNode astNode = AstNode(node, AstSymbolTypeEnum.Method); + string qName = ""; + string Name = ""; + try + { + qName = Model.GetDeclaredSymbol(node).ToString(); + Name = Model.GetDeclaredSymbol(node).Name; + } + catch (Exception) + { + FullyParsed = false; + } + string qType = ""; + try + { + qType = Model.GetSymbolInfo(node.ReturnType).Symbol.ToString(); + } + catch (Exception) + { + FullyParsed = false; + } + + CsharpMethod csharpOperator = new CsharpMethod + { + AstNode = astNode, + Name = Name, + QualifiedName = qName, + QualifiedType = qType, + DocumentationCommentXML = Model.GetDeclaredSymbol(node).GetDocumentationCommentXml(), + TypeHash = qType.GetHashCode(), + EntityHash = astNode.EntityHash, + ParentNode = parent, + MethodType = MethodTypeEnum.Operator + }; + + if (node.ParameterList.Parameters.Count > 0) + { + VisitMethodParameters(node.ParameterList.Parameters,astNode); + } + + foreach (VariableDeclarationSyntax variableDeclaration in node.DescendantNodes().OfType()) + { + VisitVariableDecl(variableDeclaration, astNode); + } + + DbContext.CsharpMethods.Add(csharpOperator); + } + + private void VisitMethodParameters(SeparatedSyntaxList parameters, CsharpAstNode parent) + { + foreach (var param in parameters) + { + CsharpAstNode astNode = AstNode(param, AstSymbolTypeEnum.Variable); + string paramQType = ""; + try + { + paramQType = Model.GetSymbolInfo(param.Type).Symbol.ToString(); + } + catch (Exception) + { + FullyParsed = false; + } + CsharpVariable varibale = new CsharpVariable + { + AstNode = astNode, + Name = param.Identifier.Text, + QualifiedType = paramQType, + TypeHash = paramQType.GetHashCode(), + EntityHash = astNode.EntityHash, + ParentNode = parent, + VariableType = VariableTypeEnum.Parameter + }; + DbContext.CsharpVariables.Add(varibale); + } + } + + private void VisitVariableDecl(VariableDeclarationSyntax node, CsharpAstNode parent) + { + foreach (var variable in node.Variables) + { + CsharpAstNode astNode = AstNode(variable, AstSymbolTypeEnum.Variable); + string varQType = ""; + bool isLINQvar = node.DescendantNodes().OfType().Any(); + try + { + if (node.Type.ToString() == "var"){ + varQType = Model.GetOperation(variable.Initializer.Value).Type.ToString(); + } else { + varQType = Model.GetSymbolInfo(node.Type).Symbol.ToString(); + } + } + catch (Exception) + { + FullyParsed = false; + } + + foreach (var member in node.DescendantNodes().OfType()) + { + isLINQvar = isLINQvar || member.DescendantNodes().OfType() + .Where(memb => new string[]{"Where", "OfType", "Select", "SelectMany"} + .Contains(memb.Identifier.ValueText)).Any(); + } + + isLINQvar = isLINQvar && (varQType.Contains("IEnumerable") + || varQType.Contains("IOrderedEnumerable") + || varQType.Contains("IQueryable")); + + //if (isLINQvar) WriteLine($"LINQvar node: '{node}' QualifiedType: '{varQType}'"); + //if (varQType == "?") WriteLine($"LINQvar ? node: '{node}' QualifiedType: '{varQType}'"); + + CsharpVariable csharpVariable = new CsharpVariable + { + AstNode = astNode, + Name = variable.Identifier.Text, + QualifiedType = varQType, + TypeHash = varQType.GetHashCode(), + DocumentationCommentXML = Model.GetDeclaredSymbol(variable).GetDocumentationCommentXml(), + EntityHash = astNode.EntityHash, + VariableType = isLINQvar ? VariableTypeEnum.LINQ : VariableTypeEnum.Variable, + ParentNode = parent + }; + DbContext.CsharpVariables.Add(csharpVariable); + } + } + + private void VisitPropertyDecl(PropertyDeclarationSyntax node, CsharpAstNode parent) + { + CsharpAstNode astNode = AstNode(node, AstSymbolTypeEnum.Variable); + string varQType = ""; + try + { + varQType = Model.GetSymbolInfo(node.Type).Symbol.ToString(); + } + catch (Exception) + { + FullyParsed = false; + } + CsharpVariable variable = new CsharpVariable + { + AstNode = astNode, + Name = node.Identifier.Text, + QualifiedType = varQType, + TypeHash = varQType.GetHashCode(), + VariableType = VariableTypeEnum.Property, + DocumentationCommentXML = Model.GetDeclaredSymbol(node).GetDocumentationCommentXml(), + EntityHash = astNode.EntityHash, + ParentNode = parent + }; + DbContext.CsharpVariables.Add(variable); + } + + private void VisitAccessors(AccessorListSyntax node, String propertyName, CsharpAstNode parent) + { + HashSet methods = new HashSet(); + + if (node == null) return; + + foreach (AccessorDeclarationSyntax accessor in node.Accessors) + { + CsharpAstNode astNode = AstNode(accessor, AstSymbolTypeEnum.Method); + + String name = ""; + switch (accessor.Kind()) + { + case SyntaxKind.GetAccessorDeclaration: + name = ".Get"; + break; + case SyntaxKind.SetAccessorDeclaration: + name = ".Set"; + break; + case SyntaxKind.InitAccessorDeclaration: + name = ".Init"; + break; + case SyntaxKind.AddAccessorDeclaration: + name = ".Add"; + break; + case SyntaxKind.RemoveAccessorDeclaration: + name = ".Remove"; + break; + case SyntaxKind.UnknownAccessorDeclaration: + name = ".Unknown"; + break; + } + + CsharpMethod method = new CsharpMethod + { + AstNode = astNode, + Name = propertyName+name+"Accessor", + DocumentationCommentXML = Model.GetDeclaredSymbol(accessor).GetDocumentationCommentXml(), + EntityHash = astNode.EntityHash, + ParentNode = parent, + MethodType = MethodTypeEnum.Accessor + }; + + foreach (VariableDeclarationSyntax variableDeclaration in accessor.DescendantNodes().OfType()) + { + VisitVariableDecl(variableDeclaration, astNode); + } + + DbContext.CsharpMethods.Add(method); + } + } + + public override void VisitEnumDeclaration(EnumDeclarationSyntax node) + { + //WriteLine($"\n EnumDeclaration visited: {node.Identifier.Text}"); + CsharpAstNode astNode = AstNode(node, AstSymbolTypeEnum.Enum); + string qName = ""; + try + { + qName = Model.GetDeclaredSymbol(node).ToString(); + } + catch (Exception) + { + FullyParsed = false; + } + + var nameSpaces = DbContext.CsharpNamespaces.Where(n => qName.Contains(n.Name)).ToList(); + CsharpNamespace csharpNamespace = null; + if (nameSpaces.Count == 1) + { + csharpNamespace = nameSpaces.First(); + } + + CsharpEnum csharpEnum = new CsharpEnum + { + CsharpNamespace = csharpNamespace, + AstNode = astNode, + Name = node.Identifier.Text, + QualifiedName = qName, + DocumentationCommentXML = Model.GetDeclaredSymbol(node).GetDocumentationCommentXml(), + EntityHash = astNode.EntityHash + }; + + foreach (EnumMemberDeclarationSyntax enumMemberDeclarationSyntax in node.Members) + { + csharpEnum.AddMember(VisitEnumMemberDecl(enumMemberDeclarationSyntax, astNode)); + } + DbContext.CsharpEnums.Add(csharpEnum); + } + + private CsharpEnumMember VisitEnumMemberDecl(EnumMemberDeclarationSyntax node, CsharpAstNode parent) + { + CsharpAstNode astNode = AstNode(node, AstSymbolTypeEnum.EnumMember); + string qName = ""; + try + { + qName = Model.GetDeclaredSymbol(node).ToString(); + } + catch (Exception) + { + FullyParsed = false; + } + CsharpEnumMember csharpEnumMember = new CsharpEnumMember + { + AstNode = astNode, + Name = node.Identifier.Text, + QualifiedName = qName, + EntityHash = astNode.EntityHash, + ParentNode = parent + }; + if (node.EqualsValue != null) + { + try + { + csharpEnumMember.EqualsValue = int.Parse(node.EqualsValue.Value.ToString()); + } + catch (FormatException) + { + //WriteLine($"Unable to parse '{node.EqualsValue.Value}'"); + } + } + DbContext.CsharpEnumMembers.Add(csharpEnumMember); + return csharpEnumMember; + } + + public override void VisitInvocationExpression(InvocationExpressionSyntax node) + { + if (node.Expression.GetFirstToken().GetNextToken().ToString() == ".") //object + { + var symbol = Model.GetSymbolInfo(node.Expression.GetFirstToken().Parent).Symbol; + if (symbol != null) + { + foreach (var declaration in symbol.DeclaringSyntaxReferences) + { + if (declaration.GetSyntax().Kind() == SyntaxKind.VariableDeclarator) + { + var doc = ""; + try + { + doc = Model.GetDeclaredSymbol(declaration.GetSyntax()) + .GetDocumentationCommentXml(); + } + catch (Exception) + { + FullyParsed = false; + } + var info = Model.GetTypeInfo(node).ConvertedType; + var declaratorNodeId = getAstNodeId(declaration.GetSyntax()); + var astNode = AstNode(node, AstSymbolTypeEnum.EtcEntity, AstTypeEnum.Usage); + CsharpEtcEntity invoc = new CsharpEtcEntity + { + AstNode = astNode, + DocumentationCommentXML = doc, + EntityHash = astNode.EntityHash, + //ParentNode = DbContext.CsharpAstNodes.Find(astNode.Id), + EtcEntityType = EtcEntityTypeEnum.Invocation, + DeclaratorNodeId = declaratorNodeId, + Name = node.Expression.GetFirstToken().ToString(), + QualifiedType = info.Name + }; + DbContext.CsharpEtcEntitys.Add(invoc); + } + } + } + } + + base.VisitInvocationExpression(node); + } + + public override void VisitIdentifierName(IdentifierNameSyntax node) + { + + var symbol = Model.GetSymbolInfo(node).Symbol; + if (symbol != null && symbol.DeclaringSyntaxReferences.Count() == 1) + { + var declaration = symbol.DeclaringSyntaxReferences.First(); + + if (declaration.GetSyntax().Kind() != SyntaxKind.CompilationUnit ) + { + var doc = ""; + var type = ""; + + try + { + var info = Model.GetTypeInfo(node).ConvertedType; + if (info != null) type = info.Name; + } + catch (Exception) + { + FullyParsed = false; + } + var kind = declaration.GetSyntax().Kind() == SyntaxKind.ForEachStatement ? + EtcEntityTypeEnum.ForeachExpr : EtcEntityTypeEnum.Invocation; + if (node.Parent.Parent.Kind() != SyntaxKind.InvocationExpression) + { + var declaratorNodeId = getAstNodeId(declaration.GetSyntax()); + var astNode = AstNode(node, AstSymbolTypeEnum.EtcEntity, AstTypeEnum.Usage); + CsharpEtcEntity expr = new CsharpEtcEntity + { + AstNode = astNode, + DocumentationCommentXML = doc, + EntityHash = astNode.EntityHash, + EtcEntityType = kind, + DeclaratorNodeId = declaratorNodeId, + Name = node.ToString(), + QualifiedType = type + }; + DbContext.CsharpEtcEntitys.Add(expr); + } + + } + + } + + base.VisitIdentifierName(node); + + } + } +} diff --git a/plugins/csharp/parser/src_csharp/CMakeLists.txt b/plugins/csharp/parser/src_csharp/CMakeLists.txt new file mode 100644 index 000000000..5f450f91a --- /dev/null +++ b/plugins/csharp/parser/src_csharp/CMakeLists.txt @@ -0,0 +1,9 @@ +add_custom_target(dotnetbuild ALL + COMMAND dotnet build -c ${DOTNET_CONFIG} -o ${CMAKE_CURRENT_BINARY_DIR}/csharp + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" +) + +install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/csharp + DESTINATION ${INSTALL_LIB_DIR} + USE_SOURCE_PERMISSIONS +) diff --git a/plugins/csharp/parser/src_csharp/CSharpParser.csproj b/plugins/csharp/parser/src_csharp/CSharpParser.csproj new file mode 100644 index 000000000..ee513d5b9 --- /dev/null +++ b/plugins/csharp/parser/src_csharp/CSharpParser.csproj @@ -0,0 +1,26 @@ + + + + Exe + net8.0 + + + + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + diff --git a/plugins/csharp/parser/src_csharp/Program.cs b/plugins/csharp/parser/src_csharp/Program.cs new file mode 100644 index 000000000..a9b2b23a5 --- /dev/null +++ b/plugins/csharp/parser/src_csharp/Program.cs @@ -0,0 +1,290 @@ +using static System.Console; +using System.Linq; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.EntityFrameworkCore; +using System; +using System.IO; +using System.Collections; +using System.Collections.Generic; +using System.Threading.Tasks; +using CSharpParser.model; + +namespace CSharpParser +{ + class Program + { + //private readonly CsharpDbContext _context; + private static List _rootDir; + private static string _buildDir = ""; + private static string _buildDirBase = ""; + private static string _connectionString = ""; + + static int Main(string[] args) + { + _rootDir = new List(); + int threadNum = 4; + + try + { + _connectionString = args[0].Replace("'", ""); + _buildDir = args[1].Replace("'", ""); + _buildDirBase = args[2].Replace("'", ""); + threadNum = int.Parse(args[3]); + + for (int i = 4; i < args.Length; ++i) + { + _rootDir.Add(args[i].Replace("'", "")); + } + } + catch (Exception e) + { + WriteLine("Error in parsing command!"); + return 1; + } + /*if (args.Length < 3) + { + WriteLine("Missing command-line arguments in CSharpParser!"); + return 1; + } + else if (args.Length == 3) + { + _connectionString = args[0].Replace("'", ""); + _rootDir = args[1].Replace("'", ""); + _buildDir = args[2].Replace("'", ""); + } + else if (args.Length == 4) + { + _connectionString = args[0].Replace("'", ""); + _rootDir = args[1].Replace("'", ""); + _buildDir = args[2].Replace("'", ""); + bool success = int.TryParse(args[3], out threadNum); + if (!success){ + WriteLine("Invalid threadnumber argument! Multithreaded parsing disabled!"); + } + } + else if (args.Length == 5) + { + _connectionString = args[0].Replace("'", ""); + _rootDir = args[1].Replace("'", ""); + _buildDir = args[2].Replace("'", ""); + _buildDirBase = args[3].Replace("'", ""); + bool success = int.TryParse(args[4], out threadNum); + if (!success) + { + WriteLine("Invalid threadnumber argument! Multithreaded parsing disabled!"); + } + } + else if (args.Length > 5) + { + WriteLine("Too many command-line arguments in CSharpParser!"); + return 1; + }*/ + + //Converting the connectionstring into entiy framwork style connectionstring + string csharpConnectionString = transformConnectionString(); + + var options = new DbContextOptionsBuilder() + .UseNpgsql(csharpConnectionString) + .Options; + + CsharpDbContext _context = new CsharpDbContext(options); + _context.Database.Migrate(); + + List allFiles = new List(); + foreach (var p in _rootDir) + { + Console.WriteLine(p); + allFiles.AddRange(GetSourceFilesFromDir(p, ".cs")); + } + + foreach (var f in allFiles) + { + WriteLine(f); + } + IEnumerable assemblies = GetSourceFilesFromDir(_buildDir, ".dll"); + IEnumerable assemblies_base = assemblies; + if (args.Length == 5) + assemblies_base = GetSourceFilesFromDir(_buildDirBase, ".dll"); + + List trees = new List(); + foreach (string file in allFiles) + { + string programText = File.ReadAllText(file); + SyntaxTree tree = CSharpSyntaxTree.ParseText(programText, null, file); + trees.Add(tree); + } + Write(trees.Count); + + CSharpCompilation compilation = CSharpCompilation.Create("CSharpCompilation") + .AddReferences(MetadataReference.CreateFromFile(typeof(object).Assembly.Location)) + .AddSyntaxTrees(trees); + + foreach (string file in assemblies_base) + { + compilation = compilation.AddReferences(MetadataReference.CreateFromFile(file)); + } + foreach (string file in assemblies) + { + compilation = compilation.AddReferences(MetadataReference.CreateFromFile(file)); + } + + var runtask = ParalellRun(csharpConnectionString, threadNum, trees, compilation); + int ret = runtask.Result; + + return 0; + } + + private static async Task ParalellRun(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 ParsingTasks = new List>(); + int maxThread = threadNum < trees.Count() ? threadNum : trees.Count(); + WriteLine(threadNum); + for (int i = 0; i < maxThread; i++) + { + ParsingTasks.Add(ParseTree(contextList[i],trees[i],compilation,i)); + } + + int nextTreeIndex = maxThread; + while (ParsingTasks.Count > 0) + { + var finshedTask = await Task.WhenAny(ParsingTasks); + int nextContextIndex = await finshedTask; + + ParsingTasks.Remove(finshedTask); + if (nextTreeIndex < trees.Count) + { + ParsingTasks.Add(ParseTree(contextList[nextContextIndex], + trees[nextTreeIndex],compilation,nextContextIndex)); + ++nextTreeIndex; + } + } + + foreach (var ctx in contextList) + { + ctx.SaveChanges(); + } + + return 0; + } + + private static async Task ParseTree(CsharpDbContext context, + SyntaxTree tree, CSharpCompilation compilation, int index) + { + var ParsingTask = Task.Run(() => + { + WriteLine("ParallelRun " + tree.FilePath); + SemanticModel model = compilation.GetSemanticModel(tree); + var visitor = new AstVisitor(context, model, tree); + visitor.Visit(tree.GetCompilationUnitRoot()); + WriteLine((visitor.FullyParsed ? "+" : "-") + tree.FilePath); + return index; + }); + return await ParsingTask; + } + + public static IEnumerable GetSourceFilesFromDir(string root, string extension) + { + IEnumerable allFiles = new string[]{}; + // Data structure to hold names of subfolders. + ArrayList dirs = new ArrayList(); + + if (!System.IO.Directory.Exists(root)) + { + throw new ArgumentException(); + } + dirs.Add(root); + + while (dirs.Count > 0) + { + string currentDir = dirs[0].ToString(); + dirs.RemoveAt(0); + string[] subDirs; + try + { + subDirs = System.IO.Directory.GetDirectories(currentDir); + } + catch (UnauthorizedAccessException e) + { + WriteLine(e.Message); + continue; + } + catch (System.IO.DirectoryNotFoundException e) + { + WriteLine(e.Message); + continue; + } + + // Add the subdirectories for traversal. + dirs.AddRange(subDirs); + + string[] files = null; + try + { + files = System.IO.Directory.GetFiles(currentDir); + } + catch (UnauthorizedAccessException e) + { + Console.WriteLine(e.Message); + continue; + } + catch (System.IO.DirectoryNotFoundException e) + { + Console.WriteLine(e.Message); + continue; + } + + foreach (string file in files) + { + try + { + System.IO.FileInfo fi = new System.IO.FileInfo(file); + if (fi.Extension == extension) { + allFiles = allFiles.Append(file); + } + } + catch (System.IO.FileNotFoundException e) + { + // If file was deleted by a separate application + Console.WriteLine(e.Message); + } + } + } + + return allFiles; + } + + private static string transformConnectionString() + { + _connectionString = _connectionString.Substring(_connectionString.IndexOf(':')+1); + _connectionString = _connectionString.Replace("user", "username"); + string [] properties = _connectionString.Split(';'); + string csharpConnectionString = ""; + for (int i = 0; i < properties.Length; ++i) + { + csharpConnectionString += properties[i].Substring(0,1).ToUpper() + + properties[i].Substring(1); + if (i < properties.Length-1) + { + csharpConnectionString += ";"; + } + } + + return csharpConnectionString; + } + } +} diff --git a/plugins/csharp/service/CMakeLists.txt b/plugins/csharp/service/CMakeLists.txt new file mode 100644 index 000000000..cfc163255 --- /dev/null +++ b/plugins/csharp/service/CMakeLists.txt @@ -0,0 +1,57 @@ +include_directories( + include + ${PROJECT_SOURCE_DIR}/model/include + ${PROJECT_SOURCE_DIR}/util/include + ${PROJECT_SOURCE_DIR}/webserver/include + ${PROJECT_BINARY_DIR}/service/language/gen-cpp + ${PROJECT_BINARY_DIR}/service/project/gen-cpp + ${PROJECT_SOURCE_DIR}/service/project/include + ${CMAKE_CURRENT_BINARY_DIR}/gen-cpp) + +include_directories(SYSTEM + ${THRIFT_LIBTHRIFT_INCLUDE_DIRS}) + +# Generate thrift files +add_custom_command( + OUTPUT + ${CMAKE_CURRENT_BINARY_DIR}/gen-cpp/CsharpService.cpp + ${CMAKE_CURRENT_BINARY_DIR}/gen-cpp + ${CMAKE_CURRENT_BINARY_DIR}/gen-netstd + COMMAND + ${THRIFT_EXECUTABLE} --gen cpp --gen netstd + -o ${CMAKE_CURRENT_BINARY_DIR} + -I ${PROJECT_SOURCE_DIR}/service + ${CMAKE_CURRENT_SOURCE_DIR}/csharpservice.thrift + DEPENDS + ${CMAKE_CURRENT_SOURCE_DIR}/csharpservice.thrift + COMMENT + "Generating Thrift for csharpservice.thrift") + +# Create cpp static library from thrift files +add_library(csharpservicethrift STATIC + ${CMAKE_CURRENT_BINARY_DIR}/gen-cpp/CsharpService.cpp) + +target_compile_options(csharpservicethrift PUBLIC -fPIC) + +add_dependencies(csharpservicethrift languagethrift commonthrift projectthrift) + +add_subdirectory(src_csharp) + +add_library(csharpservice SHARED + src/csharpservice.cpp + src/plugin.cpp) + +target_compile_options(csharpservice PUBLIC -Wno-unknown-pragmas) + +target_link_libraries(csharpservice + util + model + mongoose + csharpservicethrift + projectservice + projectthrift + languagethrift + gvc + ${THRIFT_LIBTHRIFT_LIBRARIES}) + +install(TARGETS csharpservice DESTINATION ${INSTALL_SERVICE_DIR}) \ No newline at end of file diff --git a/plugins/csharp/service/csharpservice.thrift b/plugins/csharp/service/csharpservice.thrift new file mode 100644 index 000000000..4d223da5e --- /dev/null +++ b/plugins/csharp/service/csharpservice.thrift @@ -0,0 +1,58 @@ +include "../../../service/language/language.thrift" +include "../../../service/project/common.thrift" + +namespace cpp cc.service.csharp +namespace netstd cc.service.csharp + +service CsharpService +{ + language.AstNodeInfo getAstNodeInfo(1:common.AstNodeId astNodeId) + throws (1:common.InvalidId ex) + + language.AstNodeInfo getAstNodeInfoByPosition(1:string path, 2:common.Position fpos) + throws (1:common.InvalidInput ex) + + map getProperties(1:common.AstNodeId astNodeIds) + throws (1:common.InvalidId ex) + + string getDocumentation(1:common.AstNodeId astNodeId) + throws (1:common.InvalidId ex) + + common.FileRange getFileRange(1:common.AstNodeId astNodeId) + throws (1:common.InvalidId ex) + + map getReferenceTypes(1:common.AstNodeId astNodeId) + throws (1:common.InvalidId ex) + + i32 getReferenceCount( + 1:common.AstNodeId astNodeId, + 2:i32 referenceId) + + list getReferences( + 1:common.AstNodeId astNodeId, + 2:i32 referenceId + 3:list tags) + throws (1:common.InvalidId ex) + + map getFileReferenceTypes() + throws (1:common.InvalidId ex) + + i32 getFileReferenceCount( + 1:string path, + 2:i32 referenceId) + + list getFileReferences( + 1:string path, + 2:i32 referenceId) + throws (1:common.InvalidId ex) + + 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) +} \ No newline at end of file diff --git a/plugins/csharp/service/include/service/csharpservice.h b/plugins/csharp/service/include/service/csharpservice.h new file mode 100644 index 000000000..3660098c9 --- /dev/null +++ b/plugins/csharp/service/include/service/csharpservice.h @@ -0,0 +1,341 @@ +#ifndef CC_SERVICE_CSHARP_CSHARPSERVICE_H +#define CC_SERVICE_CSHARP_CSHARPSERVICE_H + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +namespace cc +{ +namespace service +{ +namespace csharp +{ + +namespace language = cc::service::language; + +using TransportException = apache::thrift::transport::TTransportException; + +class CSharpQueryHandler : public CsharpServiceIf +{ +public: + CSharpQueryHandler() {} + + void getClientInterface(int timeoutInMs_) + { + using Transport = apache::thrift::transport::TTransport; + using BufferedTransport = apache::thrift::transport::TBufferedTransport; + using Socket = apache::thrift::transport::TSocket; + using Protocol = apache::thrift::protocol::TBinaryProtocol; + namespace ch = std::chrono; + + std::string host = "localhost"; + std::shared_ptr socket(new Socket(host, _thriftServerPort)); + std::shared_ptr transport(new BufferedTransport(socket)); + std::shared_ptr protocol(new Protocol(transport)); + + _service.reset(new CsharpServiceClient(protocol)); + + // Redirect Thrift output into std::stringstream + apache::thrift::GlobalOutput.setOutputFunction( + [](const char* x) + { + _thriftStream << x; + }); + + ch::steady_clock::time_point begin = ch::steady_clock::now(); + + while (!transport->isOpen()) + { + try + { + transport->open(); + } + catch (TransportException& ex) + { + ch::steady_clock::time_point current = ch::steady_clock::now(); + float elapsed_time = ch::duration_cast(current - begin).count(); + + if (elapsed_time > timeoutInMs_) + { + LOG(debug) << "Connection timeout, could not reach CSharp server on" + << host << ":" << _thriftServerPort; + apache::thrift::GlobalOutput.setOutputFunction( + apache::thrift::TOutput::errorTimeWrapper); + throw ex; + } + } + } + + apache::thrift::GlobalOutput.setOutputFunction( + apache::thrift::TOutput::errorTimeWrapper); + + LOG(info) << "C# server started!"; + } + + + void getAstNodeInfo( + language::AstNodeInfo& return_, + const core::AstNodeId& astNodeId_) override + { + _service -> getAstNodeInfo(return_, astNodeId_); + } + + void getAstNodeInfoByPosition( + language::AstNodeInfo& return_, + const std::string& path_, + const core::Position& fpos_) override + { + _service -> getAstNodeInfoByPosition(return_, path_, fpos_); + } + + void getFileRange( + core::FileRange& return_, + const core::AstNodeId& astNodeId_) override + { + _service -> getFileRange(return_, astNodeId_); + } + + void getProperties( + std::map& return_, + const core::AstNodeId& astNodeId_) override + { + _service -> getProperties(return_, astNodeId_); + } + + void getDocumentation( + std::string& return_, + const core::AstNodeId& astNodeId_) override + { + _service -> getDocumentation(return_, astNodeId_); + } + + void getReferenceTypes( + std::map& return_, + const core::AstNodeId& astNodeId_) override + { + _service -> getReferenceTypes(return_, astNodeId_); + } + + std::int32_t getReferenceCount( + const core::AstNodeId& astNodeId_, + const std::int32_t referenceId_) override + { + return _service -> getReferenceCount(astNodeId_, referenceId_); + } + + void getReferences( + std::vector& return_, + const core::AstNodeId& astNodeId_, + const std::int32_t referenceId_, + const std::vector& tags_) override + { + _service -> getReferences(return_, astNodeId_, referenceId_, tags_); + } + + void getFileReferenceTypes( + std::map& return_) override + { + _service -> getFileReferenceTypes(return_); + } + + std::int32_t getFileReferenceCount( + const core::FileId& fileId_, + const std::int32_t referenceId_) override + { + return _service -> getFileReferenceCount(fileId_, referenceId_); + } + + void getFileReferences( + std::vector& return_, + const core::FileId& fileId_, + const std::int32_t referenceId_) override + { + _service -> getFileReferences(return_, fileId_, referenceId_); + } + + void getDiagramTypes( + std::map& return_, + const core::AstNodeId& astNodeId_) override + { + _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_, + const std::vector& content_) override + { + _service -> getSyntaxHighlight(return_, range_, content_); + } + + void setThriftServerPort(int port) + { + _thriftServerPort = port; + } + +private: + std::unique_ptr _service; + static std::stringstream _thriftStream; + static int _thriftServerPort; +}; +} + +namespace language +{ + +using TransportException = apache::thrift::transport::TTransportException; + +class CsharpServiceHandler : virtual public LanguageServiceIf +{ + friend class Diagram; + +public: + CsharpServiceHandler( + std::shared_ptr db_, + std::shared_ptr datadir_, + const cc::webserver::ServerContext& context_); + + std::string getDbString(); + + void getFileTypes(std::vector& return_) override; + + void getAstNodeInfo( + AstNodeInfo& return_, + const core::AstNodeId& astNodeId_) override; + + void getAstNodeInfoByPosition( + AstNodeInfo& return_, + const core::FilePosition& fpos_) override; + + void getSourceText( + std::string& return_, + const core::AstNodeId& astNodeId_) override; + + void getDocumentation( + std::string& return_, + const core::AstNodeId& astNodeId_) override; + + void getProperties( + std::map& return_, + const core::AstNodeId& astNodeId_) override; + + void getDiagramTypes( + std::map& return_, + const core::AstNodeId& astNodeId_) override; + + void getDiagram( + std::string& return_, + const core::AstNodeId& astNodeId_, + const std::int32_t diagramId_) override; + + void getDiagramLegend( + std::string& return_, + const std::int32_t diagramId_) override; + + void getFileDiagramTypes( + std::map& return_, + const core::FileId& fileId_) override; + + void getFileDiagram( + std::string& return_, + const core::FileId& fileId_, + const int32_t diagramId_) override; + + void getFileDiagramLegend( + std::string& return_, + const std::int32_t diagramId_) override; + + void getReferenceTypes( + std::map& return_, + const core::AstNodeId& astNodeId) override; + + void getReferences( + std::vector& return_, + const core::AstNodeId& astNodeId_, + const std::int32_t referenceId_, + const std::vector& tags_) override; + + std::int32_t getReferenceCount( + const core::AstNodeId& astNodeId_, + const std::int32_t referenceId_) override; + + void getReferencesInFile( + std::vector& return_, + const core::AstNodeId& astNodeId_, + const std::int32_t referenceId_, + const core::FileId& fileId_, + const std::vector& tags_) override; + + void getReferencesPage( + std::vector& return_, + const core::AstNodeId& astNodeId_, + const std::int32_t referenceId_, + const std::int32_t pageSize_, + const std::int32_t pageNo_) override; + + void getFileReferenceTypes( + std::map& return_, + const core::FileId& fileId_) override; + + void getFileReferences( + std::vector& return_, + const core::FileId& fileId_, + const std::int32_t referenceId_) override; + + std::int32_t getFileReferenceCount( + const core::FileId& fileId_, + const std::int32_t referenceId_) override; + + void getSyntaxHighlight( + std::vector& return_, + const core::FileRange& range_) override; + +private: + std::shared_ptr _db; + util::OdbTransaction _transaction; + + std::shared_ptr _datadir; + const cc::webserver::ServerContext& _context; + boost::process::child c; + + cc::service::csharp::CSharpQueryHandler _csharpQueryHandler; + static int _thriftServerPort; +}; + +} // language +} // service +} // cc + +#endif // CC_SERVICE_CSHARP_CSHARPSERVICE_H diff --git a/plugins/csharp/service/src/csharpservice.cpp b/plugins/csharp/service/src/csharpservice.cpp new file mode 100644 index 000000000..7d44b417d --- /dev/null +++ b/plugins/csharp/service/src/csharpservice.cpp @@ -0,0 +1,303 @@ +#include +#include +#include +#include +#include + +namespace cc +{ +namespace service +{ +namespace language +{ +typedef odb::query FileQuery; +namespace fs = boost::filesystem; +namespace bp = boost::process; +namespace pt = boost::property_tree; + +int CsharpServiceHandler::_thriftServerPort = 9091; + +CsharpServiceHandler::CsharpServiceHandler( + std::shared_ptr db_, + std::shared_ptr datadir_, + const cc::webserver::ServerContext& context_) + : _db(db_), + _transaction(db_), + _datadir(datadir_), + _context(context_) +{ + _csharpQueryHandler.setThriftServerPort(_thriftServerPort); + fs::path csharp_path = + fs::system_complete("../lib/serviceplugin/csharpservice/"); + + std::string command("./csharpservice "); + command.append(getDbString()); + command.append(" "); + command.append(std::to_string(_thriftServerPort)); + ++_thriftServerPort; + c = bp::child(bp::start_dir(csharp_path), command); + try + { + _csharpQueryHandler.getClientInterface(25000); + } + catch (TransportException& ex) + { + LOG(error) << "[csharpservice] Starting service failed!"; + } +} + +std::string CsharpServiceHandler::getDbString() +{ + pt::ptree _pt; + pt::read_json(*_datadir + "/project_info.json", _pt); + + return _pt.get("database"); +} + +void CsharpServiceHandler::getFileTypes(std::vector& return_) +{ + //LOG(info) << "CsharpServiceHandler getFileTypes"; + return_.push_back("CS"); + return_.push_back("Dir"); +} + +void CsharpServiceHandler::getAstNodeInfo( + AstNodeInfo& return_, + const core::AstNodeId& astNodeId_) +{ + _csharpQueryHandler.getAstNodeInfo(return_, astNodeId_); + model::FilePtr file = _transaction([&, this](){ + return _db->query_one( + FileQuery::path == return_.range.file); + }); + std::stringstream ss; + ss << file; + return_.range.file = ss.str(); + //LOG(info) << "csharpQuery.getAstNodeInfo: file = " << return_.range.file; +} + +void CsharpServiceHandler::getAstNodeInfoByPosition( + AstNodeInfo& return_, + const core::FilePosition& fpos_) +{ + model::FilePtr file = _transaction([&, this](){ + return _db->query_one( + FileQuery::id == std::stoull(fpos_.file)); + }); + _csharpQueryHandler.getAstNodeInfoByPosition(return_, file->path, fpos_.pos); +} + +void CsharpServiceHandler::getSourceText( + std::string& return_, + const core::AstNodeId& astNodeId_) +{ + LOG(info) << "getSourceText"; + core::FileRange fileRange; + + _csharpQueryHandler.getFileRange(fileRange, astNodeId_); + + return_ = _transaction([&, this](){ + model::FilePtr file = _db->query_one( + FileQuery::id == std::stoull(fileRange.file)); + + if (!file) { + return std::string(); + } + + return cc::util::textRange( + file->content.load()->content, + fileRange.range.startpos.line, + fileRange.range.startpos.column, + fileRange.range.endpos.line, + fileRange.range.endpos.column); + }); +} + +void CsharpServiceHandler::getProperties( + std::map& return_, + const core::AstNodeId& astNodeId_) +{ + //LOG(info) << "getProperties"; + _csharpQueryHandler.getProperties(return_, astNodeId_); +} + +void CsharpServiceHandler::getDocumentation( + std::string& return_, + const core::AstNodeId& astNodeId_) +{ + LOG(info) << "getDocumentation"; + _csharpQueryHandler.getDocumentation(return_, astNodeId_); +} + +void CsharpServiceHandler::getDiagramTypes( + std::map& return_, + const core::AstNodeId& astNodeId_) +{ + LOG(info) << "getDiagramTypes"; + //csharpQueryHandler.getDiagramTypes(return_, astNodeId_); +} + +void CsharpServiceHandler::getDiagram( + std::string& return_, + const core::AstNodeId& astNodeId_, + const std::int32_t diagramId_) +{ + LOG(info) << "getDiagram"; + //csharpQueryHandler.getDiagram(return_, astNodeId_, diagramId_); +} + +void CsharpServiceHandler::getDiagramLegend( + std::string& return_, + const std::int32_t diagramId_) +{ + LOG(info) << "getDiagramLegend"; +} + +void CsharpServiceHandler::getFileDiagramTypes( + std::map& return_, + const core::FileId& fileId_) +{ + LOG(info) << "getFileDiagramTypes"; +} + +void CsharpServiceHandler::getFileDiagram( + std::string& return_, + const core::FileId& fileId_, + const int32_t diagramId_) +{ + LOG(info) << "getFileDiagram"; +} + +void CsharpServiceHandler::getFileDiagramLegend( + std::string& return_, + const std::int32_t diagramId_) +{ + LOG(info) << "getFileDiagramLegend"; +} + +void CsharpServiceHandler::getReferenceTypes( + std::map& return_, + const core::AstNodeId& astNodeId_) +{ + //LOG(info) << "getReferenceTypes"; + _csharpQueryHandler.getReferenceTypes(return_, astNodeId_); +} + +std::int32_t CsharpServiceHandler::getReferenceCount( + const core::AstNodeId& astNodeId_, + const std::int32_t referenceId_) +{ + //LOG(info) << "getReferenceCount"; + return _csharpQueryHandler.getReferenceCount(astNodeId_, referenceId_); +} + +void CsharpServiceHandler::getReferences( + std::vector& return_, + const core::AstNodeId& astNodeId_, + const std::int32_t referenceId_, + const std::vector& tags_) +{ + //LOG(info) << "getReferences"; + _csharpQueryHandler.getReferences(return_, astNodeId_, referenceId_, tags_); + std::vector ret; + for (AstNodeInfo nodeinfo : return_) + { + model::FilePtr file = _transaction([&, this](){ + return _db->query_one( + FileQuery::path == nodeinfo.range.file); + }); + + std::stringstream ss; + ss << file->id; + nodeinfo.range.file = ss.str(); + ret.push_back(nodeinfo); + } + return_ = ret; +} + +void CsharpServiceHandler::getReferencesInFile( + std::vector& /* return_ */, + const core::AstNodeId& /* astNodeId_ */, + const std::int32_t /* referenceId_ */, + const core::FileId& /* fileId_ */, + const std::vector& /* tags_ */) +{ + //LOG(info) << "getReferencesInFile"; + // TODO +} + +void CsharpServiceHandler::getReferencesPage( + std::vector& /* return_ */, + const core::AstNodeId& /* astNodeId_ */, + const std::int32_t /* referenceId_ */, + const std::int32_t /* pageSize_ */, + const std::int32_t /* pageNo_ */) +{ + //LOG(info) << "getReferencesPage"; + // TODO +} + +void CsharpServiceHandler::getFileReferenceTypes( + std::map& return_, + const core::FileId& /* fileId_*/) +{ + //LOG(info) << "getFileReferenceTypes"; + _csharpQueryHandler.getFileReferenceTypes(return_); +} + +std::int32_t CsharpServiceHandler::getFileReferenceCount( + const core::FileId& fileId_, + const std::int32_t referenceId_) +{ + //LOG(info) << "getFileReferenceCount"; + model::FilePtr file = _transaction([&, this](){ + return _db->query_one( + FileQuery::id == std::stoull(fileId_)); + }); + return _csharpQueryHandler.getFileReferenceCount(file->path, referenceId_); +} + +void CsharpServiceHandler::getFileReferences( + std::vector& return_, + const core::FileId& fileId_, + const std::int32_t referenceId_) +{ + //LOG(info) << "getFileReferences"; + model::FilePtr file = _transaction([&, this](){ + return _db->query_one( + FileQuery::id == std::stoull(fileId_)); + }); + _csharpQueryHandler.getFileReferences(return_, file->path, referenceId_); +} + +void CsharpServiceHandler::getSyntaxHighlight( + std::vector& return_, + const core::FileRange& range_) +{ + LOG(info) << "getSyntaxHighlight"; + /* + std::vector content; + _transaction([&, this]() { + //--- Load the file content and break it into lines ---// + model::FilePtr file = _db->query_one( + FileQuery::id == std::stoull(range_.file)); + if (!file || !file->content.load()) + return; + std::istringstream s(file->content->content); + std::string line; + while (std::getline(s, line)) + content.push_back(line); + }); + csharpQueryHandler.getSyntaxHighlight(return_, range_, content); + */ +} + +} // language + +namespace csharp +{ +std::stringstream CSharpQueryHandler::_thriftStream; +int CSharpQueryHandler::_thriftServerPort; +} +} // service +} // cc diff --git a/plugins/csharp/service/src/plugin.cpp b/plugins/csharp/service/src/plugin.cpp new file mode 100644 index 000000000..1d2081114 --- /dev/null +++ b/plugins/csharp/service/src/plugin.cpp @@ -0,0 +1,26 @@ +#include + +#include + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wreturn-type-c-linkage" +extern "C" +{ + boost::program_options::options_description getOptions() + { + boost::program_options::options_description description("C# Plugin"); + return description; + } + + void registerPlugin( + const cc::webserver::ServerContext& context_, + cc::webserver::PluginHandler* pluginHandler_) + { + cc::webserver::registerPluginSimple( + context_, + pluginHandler_, + CODECOMPASS_LANGUAGE_SERVICE_FACTORY_WITH_CFG(Csharp), + "CsharpService"); + } +} +#pragma clang diagnostic pop diff --git a/plugins/csharp/service/src_csharp/CMakeLists.txt b/plugins/csharp/service/src_csharp/CMakeLists.txt new file mode 100644 index 000000000..b6663eb88 --- /dev/null +++ b/plugins/csharp/service/src_csharp/CMakeLists.txt @@ -0,0 +1,33 @@ +add_custom_target(dotnetbuildservice + COMMAND ${THRIFT_EXECUTABLE} --gen netstd + -o ${CMAKE_CURRENT_BINARY_DIR} + -I ${PROJECT_SOURCE_DIR}/service + -r ${CMAKE_CURRENT_SOURCE_DIR}/../csharpservice.thrift + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" +) + +add_custom_target(dotnetaddclasslib + COMMAND dotnet new classlib -o ${CMAKE_CURRENT_BINARY_DIR}/gen-netstd/ -f "net8.0" --force + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" +) + +add_dependencies(dotnetaddclasslib dotnetbuildservice) + +add_custom_target(dotnetaddthriftlib + COMMAND dotnet add package ApacheThrift --version 0.16.0 + WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/gen-netstd/" +) + +add_dependencies(dotnetaddthriftlib dotnetaddclasslib) + +add_custom_target(dotnetbuildfiles ALL + COMMAND dotnet build -c ${DOTNET_CONFIG} -o ${CMAKE_CURRENT_BINARY_DIR}/csharpservice -p:BuildDir=${CMAKE_CURRENT_BINARY_DIR} + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" +) + +add_dependencies(dotnetbuildfiles dotnetaddthriftlib) + +install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/csharpservice + DESTINATION ${INSTALL_SERVICE_DIR} + USE_SOURCE_PERMISSIONS +) diff --git a/plugins/csharp/service/src_csharp/CSharpQueryHandler.cs b/plugins/csharp/service/src_csharp/CSharpQueryHandler.cs new file mode 100644 index 000000000..a221b65b9 --- /dev/null +++ b/plugins/csharp/service/src_csharp/CSharpQueryHandler.cs @@ -0,0 +1,684 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net.Security; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.EntityFrameworkCore; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using System.Diagnostics; +using language; +using cc.service.csharp; +using CSharpParser.model; + +public class CSharpQueryHandler : CsharpService.IAsync +{ + private CsharpDbContext dbContext; + public CSharpQueryHandler(string connenctionString) + { + // Converting the connectionstring into Entity Framework style connection string + connenctionString = connenctionString.Substring(connenctionString.IndexOf(':')+1); + connenctionString = connenctionString.Replace("user", "username"); + string[] properties = connenctionString.Split(';'); + string csharpConnenctionString = ""; + for (int i = 0; i < properties.Length; ++i) + { + csharpConnenctionString += properties[i].Substring(0,1).ToUpper() + + properties[i].Substring(1); + if (i < properties.Length-1) + { + csharpConnenctionString += ";"; + } + } + + var options = new DbContextOptionsBuilder() + .UseNpgsql(csharpConnenctionString) + .Options; + dbContext = new CsharpDbContext(options); + } + + private language.AstNodeInfo createAstNodeInfo(CsharpAstNode node) + { + language.AstNodeInfo ret = new language.AstNodeInfo(); + ret.Id = node.Id.ToString(); + ret.AstNodeValue = node.AstValue; + ret.AstNodeType = node.RawKind.ToString(); + ret.SymbolType = node.AstSymbolType.ToString(); + ret.Range = getFileRange(node); + + List tags = new List(); + tags.Add(node.Accessibility.ToString()); + + ret.Tags = tags; + + return ret; + } + + private List createAstNodeInfoList(List nodeList) + { + var ret = new List(); + foreach (var node in nodeList) + { + var astNodeInfo = createAstNodeInfo(node); + ret.Add(astNodeInfo); + } + + return ret; + } + + private FileRange getFileRange(CsharpAstNode node) + { + FileRange fileRange = new FileRange(); + Position startPosition = new Position + { + Line = (int)node.Location_range_start_line, + Column = (int)node.Location_range_start_column + }; + + Position endPosition = new Position + { + Line = (int)node.Location_range_end_line, + Column = (int)node.Location_range_end_column + }; + + Range range = new Range + { + Startpos = startPosition, + Endpos = endPosition + }; + + fileRange.File = node.Path; + fileRange.Range = range; + + return fileRange; + } + + private CsharpAstNode queryCsharpAstNode(string astNodeId) + { + CsharpAstNode ret; + try + { + ret = dbContext.CsharpAstNodes + .Where(a => a.Id.ToString()==astNodeId) + .First(); + } + catch (InvalidOperationException e) + { + System.Console.WriteLine($"[CSharpService error] There are no AstNode with this ID:{astNodeId}"); + ret = new CsharpAstNode(); + ret.Id = 0; + } + return ret; + } + + private List queryInvocations(CsharpAstNode astNode) + { + var ret = dbContext.CsharpEtcEntitys + .Where(e => e.DeclaratorNodeId == astNode.Id) + .Select(e => e.AstNode) + .ToList(); + return ret; + } + + private List queryDeclarators(CsharpAstNode astNode) + { + var ids = dbContext.CsharpEtcEntitys + .Where(e => e.AstNode.Id == astNode.Id) + .Select(e => e.DeclaratorNodeId.ToString()) + .ToList(); + + if (ids.Count == 0) + { + return new List(); + } + else + { + return ids.Select(id => queryCsharpAstNode(id)).ToList(); + } + } + + private List queryEvals(CsharpAstNode astNode) + { + var ret = + from invoc in dbContext.CsharpEtcEntitys + join variable in dbContext.CsharpVariables + on invoc.DeclaratorNodeId equals variable.AstNode.Id + where invoc.DeclaratorNodeId == astNode.Id + && variable.VariableType == VariableTypeEnum.LINQ + && (invoc.QualifiedType != "IEnumerable" + || invoc.EtcEntityType == EtcEntityTypeEnum.ForeachExpr) + select invoc.AstNode; + return ret.ToList(); + } + + private List queryParams(CsharpAstNode astNode) + { + var ret = dbContext.CsharpVariables + .Where(e => e.ParentNode.Id == astNode.Id + && e.VariableType == VariableTypeEnum.Parameter) + .Select(e => e.AstNode) + .ToList(); + return ret; + } + + private List queryLocals(CsharpAstNode astNode){ + var ret = dbContext.CsharpVariables + .Where(e => e.ParentNode.Id == astNode.Id + && e.VariableType == VariableTypeEnum.Variable) + .Select(e => e.AstNode) + .ToList(); + return ret; + } + + private List queryProperties(CsharpAstNode astNode) + { + var ret = dbContext.CsharpVariables + .Where(e => e.ParentNode.Id == astNode.Id + && e.VariableType == VariableTypeEnum.Property) + .Select(e => e.AstNode) + .ToList(); + return ret; + } + + private List queryCalls(CsharpAstNode astNode) + { + var ret = + from invoc in dbContext.CsharpEtcEntitys + join node in dbContext.CsharpAstNodes + on invoc.DeclaratorNodeId equals node.Id + where node.AstSymbolType == AstSymbolTypeEnum.Method + && 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 + select invoc.AstNode; + return ret.ToList(); + } + + private List queryCallees(CsharpAstNode astNode) + { + var ret = + from invoc in dbContext.CsharpEtcEntitys + join node in dbContext.CsharpAstNodes + on invoc.DeclaratorNodeId equals node.Id + where node.AstSymbolType == AstSymbolTypeEnum.Method + && 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 + select node; + return ret.Distinct().ToList(); + } + + private List queryCallers(CsharpAstNode astNode) + { + var invocations = dbContext.CsharpEtcEntitys + .Where(e => e.DeclaratorNodeId == astNode.Id) + .Select(e => e.AstNode); + var ret = + from invoc in invocations + join node in dbContext.CsharpAstNodes + on invoc.Path equals node.Path + where node.AstSymbolType == AstSymbolTypeEnum.Method + && invoc.Location_range_start_line >= node.Location_range_start_line + && invoc.Location_range_end_line <= node.Location_range_end_line + select node; + return ret.Distinct().ToList(); + } + + private List queryEnumConsts(CsharpAstNode astNode) + { + var ret = new List(); + if (astNode.AstSymbolType == AstSymbolTypeEnum.Enum) + { + ret = dbContext.CsharpEnumMembers + .Where(e => e.ParentNode.Id == astNode.Id) + .Select(e => e.AstNode) + .ToList(); + } + else if (astNode.AstSymbolType == AstSymbolTypeEnum.EnumMember) + { + var parent = dbContext.CsharpEnumMembers + .Where(e => e.AstNode.Id == astNode.Id) + .Select(e => e.ParentNode).FirstOrDefault(); + + ret = dbContext.CsharpEnumMembers + .Where(e => e.ParentNode.Id == parent.Id) + .Select(e => e.AstNode) + .ToList(); + } + + return ret; + } + + private List queryMethods(CsharpAstNode astNode) + { + var ret = dbContext.CsharpMethods + .Where(e => e.ParentNode.Id == astNode.Id) + .Select(e => e.AstNode) + .ToList(); + return ret; + } + + private List queryMethodType(CsharpAstNode astNode, MethodTypeEnum type) + { + var ret = dbContext.CsharpMethods + .Where(e => e.ParentNode.Id == astNode.Id + && e.MethodType == type) + .Select(e => e.AstNode) + .ToList(); + return ret; + } + + private List queryEvents(CsharpAstNode astNode) + { + var ret = dbContext.CsharpEtcEntitys + .Where(e => e.ParentNode.Id == astNode.Id + && e.EtcEntityType == EtcEntityTypeEnum.Event) + .Select(e => e.AstNode) + .ToList(); + return ret; + } + + + public async Task getAstNodeInfo(string astNodeId, + CancellationToken cancellationToken = default(CancellationToken)) + { + System.Console.WriteLine("[CSharpService] getAstNodeInfoAsync"); + return await Task.FromResult(new language.AstNodeInfo()); + } + + public async Task getAstNodeInfoByPosition(string path_, + Position pos_, + CancellationToken cancellationToken = default(CancellationToken)) + { + var nodes = dbContext.CsharpAstNodes + .Where(a => + a.Path == path_ && + ((a.Location_range_start_line == pos_.Line && + a.Location_range_start_column <= pos_.Column) || + a.Location_range_start_line < pos_.Line) && + ((a.Location_range_end_line == pos_.Line && + a.Location_range_end_column > pos_.Column) || + a.Location_range_end_line > pos_.Line)); + if (nodes.Count() == 0) + { + System.Console.WriteLine("[CSharpService error] There are no AstNode at this position!"); + return await Task.FromResult(new language.AstNodeInfo()); + } + + var minNode = nodes.FirstOrDefault(); + foreach (var node in nodes.ToList()) + { + if (node.isRangeSmaller(minNode)) + minNode = node; + } + + return await Task.FromResult(createAstNodeInfo(minNode)); + } + + public async Task> getProperties(string astNodeIds, + CancellationToken cancellationToken = default(CancellationToken)) + { + Dictionary ret = new Dictionary(); + CsharpAstNode node = queryCsharpAstNode(astNodeIds); + ret.Add("AstNode Type", node.RawKind.ToString()); + ret.Add("Accessibility", node.Accessibility.ToString()); + switch(node.AstSymbolType){ + case AstSymbolTypeEnum.Variable: + var variable = dbContext.CsharpVariables + .Where(v => v.AstNode == node) + .FirstOrDefault(); + ret.Add("Name", variable.Name+" "); + ret.Add("Qualified Name", variable.QualifiedName+" "); + ret.Add("Documentation Comment", variable.DocumentationCommentXML+" "); + ret.Add("Qualified Type", variable.QualifiedType+" "); + ret.Add("Variable Type", variable.VariableType.ToString()); + break; + case AstSymbolTypeEnum.Method: + var method = dbContext.CsharpMethods + .Where(m => m.AstNode == node) + .FirstOrDefault(); + ret.Add("Name", method.Name+" "); + ret.Add("Qualified Name", method.QualifiedName+" "); + ret.Add("Documentation Comment", method.DocumentationCommentXML+" "); + ret.Add("Qualified Type", method.QualifiedType+" "); + ret.Add("Method Type", method.MethodType.ToString()); + break; + case AstSymbolTypeEnum.Class: + var Class = dbContext.CsharpClasses + .Where(m => m.AstNode == node) + .FirstOrDefault(); + ret.Add("Name", Class.Name+" "); + ret.Add("Qualified Name", Class.QualifiedName+" "); + ret.Add("Documentation Comment", Class.DocumentationCommentXML+" "); + if (Class.CsharpNamespace != null) ret.Add("Namespace", Class.CsharpNamespace.Name+" "); + ret.Add("Class Type", Class.ClassType.ToString()); + break; + case AstSymbolTypeEnum.Struct: + var Struct = dbContext.CsharpClasses + .Where(m => m.AstNode == node) + .FirstOrDefault(); + ret.Add("Name", Struct.Name+" "); + ret.Add("Qualified Name", Struct.QualifiedName+" "); + ret.Add("Documentation Comment", Struct.DocumentationCommentXML+" "); + if (Struct.CsharpNamespace != null) ret.Add("Namespace", Struct.CsharpNamespace.Name+" "); + break; + case AstSymbolTypeEnum.Namespace: + var Namespace = dbContext.CsharpNamespaces + .Where(m => m.AstNode == node) + .FirstOrDefault(); + ret.Add("Name", Namespace.Name+" "); + ret.Add("Qualified Name", Namespace.QualifiedName+" "); + ret.Add("Documentation Comment", Namespace.DocumentationCommentXML+" "); + break; + case AstSymbolTypeEnum.Enum: + var Enum = dbContext.CsharpEnums + .Where(m => m.AstNode == node) + .FirstOrDefault(); + ret.Add("Name", Enum.Name+" "); + ret.Add("Qualified Name", Enum.QualifiedName+" "); + ret.Add("Documentation Comment", Enum.DocumentationCommentXML+" "); + ret.Add("Namespace", Enum.CsharpNamespace.Name+" "); + break; + case AstSymbolTypeEnum.EnumMember: + var EnumMember = dbContext.CsharpEnumMembers + .Where(m => m.AstNode == node) + .FirstOrDefault(); + ret.Add("Name", EnumMember.Name+" "); + ret.Add("Qualified Name", EnumMember.QualifiedName+" "); + ret.Add("Documentation Comment", EnumMember.DocumentationCommentXML+" "); + ret.Add("Value", EnumMember.EqualsValue.ToString()); + break; + case AstSymbolTypeEnum.EtcEntity: + var EtcEntity = dbContext.CsharpEtcEntitys + .Where(m => m.AstNode == node) + .FirstOrDefault(); + ret.Add("Name", EtcEntity.Name+" "); + ret.Add("Qualified Name", EtcEntity.QualifiedName+" "); + ret.Add("Qualified Type", EtcEntity.QualifiedType+" "); + ret.Add("Documentation Comment", EtcEntity.DocumentationCommentXML+" "); + ret.Add("Etc Entity Type", EtcEntity.EtcEntityType.ToString()); + break; + default: + System.Console.WriteLine($"[CSharpService] {node.AstSymbolType} kind is unhandled"); + break; + } + return await Task.FromResult(ret); + } + + public async Task getDocumentation(string astNodeId, + CancellationToken cancellationToken = default(CancellationToken)) + { + System.Console.WriteLine("[CSharpService] getDocumentationAsync"); + CsharpAstNode node = queryCsharpAstNode(astNodeId); + return await Task.FromResult("Documentation"); + } + + public async Task getFileRange(string astNodeId, + CancellationToken cancellationToken = default(CancellationToken)) + { + return await Task.FromResult(getFileRange(queryCsharpAstNode(astNodeId))); + } + + public async Task> getReferenceTypes(string astNodeId, + CancellationToken cancellationToken = default(CancellationToken)) + { + var node = queryCsharpAstNode(astNodeId); + Dictionary ret = new Dictionary(); + ret.Add("Definition", (int)ReferenceType.DEFINITION); + ret.Add("Declaration", (int)ReferenceType.DECLARATION); + ret.Add("Usage", (int)ReferenceType.USAGE); + switch (node.AstSymbolType) + { + case AstSymbolTypeEnum.Variable: + var variable = dbContext.CsharpVariables + .Where(v => v.AstNode == node) + .FirstOrDefault(); + ret.Add("Reads", (int)ReferenceType.READ); + ret.Add("Writes", (int)ReferenceType.WRITE); + ret.Add("Type", (int)ReferenceType.TYPE); + if (variable.VariableType == VariableTypeEnum.LINQ) + { + ret.Add("LINQ evaluation", (int)ReferenceType.EVALUATION); + ret.Add("LINQ data modification", (int)ReferenceType.DATA_MODIFICATION); + } + break; + case AstSymbolTypeEnum.Method: + ret.Add("This calls", (int)ReferenceType.THIS_CALLS); + ret.Add("Callee", (int)ReferenceType.CALLEE); + ret.Add("Caller", (int)ReferenceType.CALLER); + ret.Add("Parameters", (int)ReferenceType.PARAMETER); + ret.Add("Local variables", (int)ReferenceType.LOCAL_VAR); + break; + case AstSymbolTypeEnum.Class: + ret.Add("Aliases", (int)ReferenceType.ALIAS); + ret.Add("Inherits from", (int)ReferenceType.INHERIT_FROM); + ret.Add("Inherited by", (int)ReferenceType.INHERIT_BY); + ret.Add("Data members", (int)ReferenceType.DATA_MEMBER); + ret.Add("Methods", (int)ReferenceType.METHOD); + ret.Add("Accesors", (int)ReferenceType.ACCESSOR); + ret.Add("Operators", (int)ReferenceType.OPERATOR); + ret.Add("Constructors", (int)ReferenceType.CONSTRUCTOR); + ret.Add("Delegates", (int)ReferenceType.DELEGATE); + ret.Add("Destructors", (int)ReferenceType.DESTRUCTOR); + ret.Add("Global variables", (int)ReferenceType.LOCAL_VAR); + break; + case AstSymbolTypeEnum.Struct: + ret.Add("Aliases", (int)ReferenceType.ALIAS); + ret.Add("Inherits from", (int)ReferenceType.INHERIT_FROM); + ret.Add("Inherited by", (int)ReferenceType.INHERIT_BY); + ret.Add("Data member", (int)ReferenceType.DATA_MEMBER); + ret.Add("Methods", (int)ReferenceType.METHOD); + ret.Add("Accesors", (int)ReferenceType.ACCESSOR); + ret.Add("Operators", (int)ReferenceType.OPERATOR); + ret.Add("Constructors", (int)ReferenceType.CONSTRUCTOR); + ret.Add("Delegates", (int)ReferenceType.DELEGATE); + ret.Add("Destructors", (int)ReferenceType.DESTRUCTOR); + ret.Add("Global variables", (int)ReferenceType.LOCAL_VAR); + break; + case AstSymbolTypeEnum.Namespace: + ret.Add("Aliases", (int)ReferenceType.ALIAS); + break; + case AstSymbolTypeEnum.Enum: + ret.Add("Enum constants", (int)ReferenceType.ENUM_CONSTANTS); + break; + case AstSymbolTypeEnum.EnumMember: + ret.Add("Enum constants", (int)ReferenceType.ENUM_CONSTANTS); + break; + case AstSymbolTypeEnum.EtcEntity: + ret.Add("Aliases", (int)ReferenceType.ALIAS); + ret.Add("Callee", (int)ReferenceType.CALLEE); + ret.Add("Caller", (int)ReferenceType.CALLER); + break; + default: + System.Console.WriteLine($"[CSharpService] {node.AstSymbolType} kind is unhandled"); + break; + } + + return await Task.FromResult(ret); + } + + public async Task getReferenceCount(string astNodeId, int referenceId, + CancellationToken cancellationToken = default(CancellationToken)) + { + var node = queryCsharpAstNode(astNodeId); + int ret = 0; + switch ((ReferenceType)referenceId) + { + case ReferenceType.USAGE: + ret = queryInvocations(node).Count(); + break; + case ReferenceType.DEFINITION: + case ReferenceType.DECLARATION: + ret = queryDeclarators(node).Count(); + break; + case ReferenceType.EVALUATION: + ret = queryEvals(node).Count(); + break; + case ReferenceType.PARAMETER: + ret = queryParams(node).Count(); + break; + case ReferenceType.LOCAL_VAR: + ret = queryLocals(node).Count(); + break; + case ReferenceType.DATA_MEMBER: + ret = queryProperties(node).Count(); + break; + case ReferenceType.THIS_CALLS: + ret = queryCalls(node).Count(); + break; + case ReferenceType.CALLEE: + ret = queryCallees(node).Count(); + break; + case ReferenceType.CALLER: + ret = queryCallers(node).Count(); + break; + case ReferenceType.ENUM_CONSTANTS: + ret = queryEnumConsts(node).Count(); + break; + case ReferenceType.METHOD: + ret = queryMethods(node).Count(); + break; + case ReferenceType.CONSTRUCTOR: + ret = queryMethodType(node, MethodTypeEnum.Constructor).Count(); + break; + case ReferenceType.DESTRUCTOR: + ret = queryMethodType(node, MethodTypeEnum.Destuctor).Count(); + break; + case ReferenceType.OPERATOR: + ret = queryMethodType(node, MethodTypeEnum.Operator).Count(); + break; + case ReferenceType.ACCESSOR: + ret = queryMethodType(node, MethodTypeEnum.Accessor).Count(); + break; + case ReferenceType.DELEGATE: + ret = queryMethodType(node, MethodTypeEnum.Delegate).Count(); + break; + case ReferenceType.EVENT: + ret = queryEvents(node).Count(); + break; + default: + System.Console.WriteLine($"[CSharpService] {(ReferenceType)referenceId}"+ + " ReferenceType is unhandled"); + break; + } + return await Task.FromResult(ret); + } + + public async Task> getReferences(string astNodeId, + int referenceId, List tags, + CancellationToken cancellationToken = default(CancellationToken)) + { + var node = queryCsharpAstNode(astNodeId); + var ret = new List(); + switch ((ReferenceType)referenceId) + { + case ReferenceType.USAGE: + ret = createAstNodeInfoList(queryInvocations(node)); + break; + case ReferenceType.DEFINITION: + case ReferenceType.DECLARATION: + ret = createAstNodeInfoList(queryDeclarators(node)); + break; + case ReferenceType.EVALUATION: + ret = createAstNodeInfoList(queryEvals(node)); + break; + case ReferenceType.PARAMETER: + ret = createAstNodeInfoList(queryParams(node)); + break; + case ReferenceType.LOCAL_VAR: + ret = createAstNodeInfoList(queryLocals(node)); + break; + case ReferenceType.DATA_MEMBER: + ret = createAstNodeInfoList(queryProperties(node)); + break; + case ReferenceType.THIS_CALLS: + ret = createAstNodeInfoList(queryCalls(node)); + break; + case ReferenceType.CALLEE: + ret = createAstNodeInfoList(queryCallees(node)); + break; + case ReferenceType.CALLER: + ret = createAstNodeInfoList(queryCallers(node)); + break; + case ReferenceType.ENUM_CONSTANTS: + ret = createAstNodeInfoList(queryEnumConsts(node)); + break; + case ReferenceType.METHOD: + ret = createAstNodeInfoList(queryMethods(node)); + break; + case ReferenceType.CONSTRUCTOR: + ret = createAstNodeInfoList(queryMethodType(node, MethodTypeEnum.Constructor)); + break; + case ReferenceType.DESTRUCTOR: + ret = createAstNodeInfoList(queryMethodType(node, MethodTypeEnum.Destuctor)); + break; + case ReferenceType.OPERATOR: + ret = createAstNodeInfoList(queryMethodType(node, MethodTypeEnum.Operator)); + break; + case ReferenceType.ACCESSOR: + ret = createAstNodeInfoList(queryMethodType(node, MethodTypeEnum.Accessor)); + break; + case ReferenceType.DELEGATE: + ret = createAstNodeInfoList(queryMethodType(node, MethodTypeEnum.Delegate)); + break; + case ReferenceType.EVENT: + ret = createAstNodeInfoList(queryEvents(node)); + break; + default: + System.Console.WriteLine($"[CSharpService] {(ReferenceType)referenceId}"+ + " ReferenceType is unhandled"); + break; + } + return await Task.FromResult(ret); + } + + public async Task> getFileReferenceTypes( + CancellationToken cancellationToken = default(CancellationToken)) + { + var ret = new Dictionary(); + ret.Add("Types", (int)FileReferenceType.TYPES); + ret.Add("Functions", (int)FileReferenceType.FUNCTIONS); + ret.Add("Includes", (int)FileReferenceType.INCLUDES); + return await Task.FromResult(ret); + } + + public async Task getFileReferenceCount(string path, int referenceId, + CancellationToken cancellationToken = default(CancellationToken)) + { + return await Task.FromResult(0); + } + + public async Task> getFileReferences(string path, + int referenceId, + CancellationToken cancellationToken = default(CancellationToken)) + { + return await Task.FromResult(new List()); + } + + public async Task> getDiagramTypes(string astNodeId, + CancellationToken cancellationToken = default(CancellationToken)) + { + return await Task.FromResult(new Dictionary()); + } + + public async Task getDiagram(string astNodeId, int diagramId, + CancellationToken cancellationToken = default(CancellationToken)) + { + return await Task.FromResult("Diagram"); + } + + public async Task> getSyntaxHighlight(FileRange range, + List content, + CancellationToken cancellationToken = default(CancellationToken)) + { + return await Task.FromResult(new List()); + } + + +} \ No newline at end of file diff --git a/plugins/csharp/service/src_csharp/CSharpQueryServer.cs b/plugins/csharp/service/src_csharp/CSharpQueryServer.cs new file mode 100644 index 000000000..955de23a1 --- /dev/null +++ b/plugins/csharp/service/src_csharp/CSharpQueryServer.cs @@ -0,0 +1,98 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net.Security; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Thrift; +using Thrift.Protocol; +using Thrift.Server; +using Thrift.Transport; +using Thrift.Transport.Server; +using Thrift.Processor; +using System.Diagnostics; +using language; +using cc.service.csharp; +using CSharpParser.model; + +namespace Server +{ + public static class LoggingHelper + { + public static ILoggerFactory LogFactory { get; } = LoggerFactory.Create(builder => { + ConfigureLogging(builder); + }); + + public static void ConfigureLogging(ILoggingBuilder logging) + { + logging.SetMinimumLevel(LogLevel.Trace); + logging.AddConsole(); + logging.AddDebug(); + } + + public static ILogger CreateLogger() => LogFactory.CreateLogger(); + } + + public class CSharpQueryServer + { + private static readonly ILogger Logger = LoggingHelper.CreateLogger(); + private static readonly TConfiguration Configuration = new TConfiguration(); + private static int port = 9091; + + /* + * args[0]: database connection string + * args[1]: Thrift server port number + */ + public static void Main(string[] args) + { + System.Console.WriteLine("New query server"); + using (var source = new CancellationTokenSource()) + { + string connenctionString = args[0]; + port = Int32.Parse(args[1]); + System.Console.WriteLine("[CSharpService] Server started!"); + RunAsync(source.Token, connenctionString).GetAwaiter().GetResult(); + + System.Console.WriteLine("[CSharpService] Press any key to stop..."); + + Console.ReadLine(); + source.Cancel(); + System.Console.WriteLine("[CSharpService] Server stopped"); + } + } + + private static async Task RunAsync(CancellationToken cancellationToken, string connenctionString) + { + TServerTransport serverTransport = new TServerSocketTransport(port, Configuration); + TTransportFactory transportFactory = new TBufferedTransport.Factory(); + TProtocolFactory protocolFactory = new TBinaryProtocol.Factory(); + + var handler = new CSharpQueryHandler(connenctionString); + ITAsyncProcessor processor = new CsharpService.AsyncProcessor(handler); + + try + { + var server = new TSimpleAsyncServer( + itProcessorFactory: new TSingletonProcessorFactory(processor), + serverTransport: serverTransport, + inputTransportFactory: transportFactory, + outputTransportFactory: transportFactory, + inputProtocolFactory: protocolFactory, + outputProtocolFactory: protocolFactory, + logger: LoggingHelper.CreateLogger()); + + await server.ServeAsync(cancellationToken); + } + catch (Exception x) + { + Logger.LogInformation("{x}",x); + } + } + } +} diff --git a/plugins/csharp/service/src_csharp/CSharpServiceEnums.cs b/plugins/csharp/service/src_csharp/CSharpServiceEnums.cs new file mode 100644 index 000000000..8046956b6 --- /dev/null +++ b/plugins/csharp/service/src_csharp/CSharpServiceEnums.cs @@ -0,0 +1,142 @@ +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 +}; + +enum FileReferenceType +{ +INCLUDES, /*!< Included source files in the current source file after the + inclusion directive. */ + +TYPES, /*!< User defined data types such as classes, structs etc. */ + +FUNCTIONS, /*!< Functions in the current source file. */ + +MACROS, /*!< Macros in the current source file. */ +}; + +enum DiagramType +{ +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. */ +}; \ No newline at end of file diff --git a/plugins/csharp/service/src_csharp/csharpservice.csproj b/plugins/csharp/service/src_csharp/csharpservice.csproj new file mode 100644 index 000000000..091a93f6c --- /dev/null +++ b/plugins/csharp/service/src_csharp/csharpservice.csproj @@ -0,0 +1,28 @@ + + + + Exe + net8.0 + + + + + + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + diff --git a/plugins/csharp/webgui/js/csharpDiagram.js b/plugins/csharp/webgui/js/csharpDiagram.js new file mode 100644 index 000000000..32b3c7caf --- /dev/null +++ b/plugins/csharp/webgui/js/csharpDiagram.js @@ -0,0 +1,99 @@ +require([ + 'dojo/topic', + 'dijit/Menu', + 'dijit/MenuItem', + 'dijit/PopupMenuItem', + 'codecompass/model', + 'codecompass/viewHandler'], +function (topic, Menu, MenuItem, PopupMenuItem, model, viewHandler) { + model.addService('csharpservice', 'CsharpService', LanguageServiceClient); + + var astDiagram = { + id : 'csharp-ast-diagram', + + getDiagram : function (diagramType, nodeId, callback) { + model.csharpservice.getDiagram(nodeId, diagramType, callback); + }, + + getDiagramLegend : function (diagramType) { + return model.csharpservice.getDiagramLegend(diagramType); + }, + + mouseOverInfo : function (diagramType, nodeId) { + var nodeInfo = model.csharpservice.getAstNodeInfo(nodeId); + var range = nodeInfo.range.range; + + return { + fileId : nodeInfo.range.file, + selection : [ + range.startpos.line, + range.startpos.column, + range.endpos.line, + range.endpos.column + ] + }; + } + }; + + viewHandler.registerModule(astDiagram, { + type : viewHandler.moduleType.Diagram + }); + + var fileDiagramHandler = { + id : 'csharp-file-diagram-handler', + + getDiagram : function (diagramType, nodeId, callback) { + model.csharpservice.getFileDiagram(nodeId, diagramType, callback); + }, + + getDiagramLegend : function (diagramType) { + return model.csharpservice.getFileDiagramLegend(diagramType); + }, + + mouseOverInfo : function (diagramType, nodeId) { + return { + fileId : nodeId, + selection : [1,1,1,1] + }; + } + }; + + viewHandler.registerModule(fileDiagramHandler, { + type : viewHandler.moduleType.Diagram + }); + + var fileDiagrams = { + id : 'csharp-file-diagrams', + render : function (fileInfo) { + var submenu = new Menu(); + + var diagramTypes = model.csharpservice.getFileDiagramTypes(fileInfo.id); + for (diagramType in diagramTypes) + submenu.addChild(new MenuItem({ + label : diagramType, + type : diagramType, + onClick : function () { + var that = this; + + topic.publish('codecompass/openFile', { fileId : fileInfo.id }); + + topic.publish('codecompass/openDiagram', { + handler : 'csharp-file-diagram-handler', + diagramType : diagramTypes[that.type], + node : fileInfo.id + }); + } + })); + + if (Object.keys(diagramTypes).length !== 0) + return new PopupMenuItem({ + label : 'C++ Diagrams', + popup : submenu + }); + } + }; + + viewHandler.registerModule(fileDiagrams, { + type : viewHandler.moduleType.FileManagerContextMenu + }); +}); diff --git a/plugins/csharp/webgui/js/csharpInfoTree.js b/plugins/csharp/webgui/js/csharpInfoTree.js new file mode 100644 index 000000000..9377ac3f0 --- /dev/null +++ b/plugins/csharp/webgui/js/csharpInfoTree.js @@ -0,0 +1,373 @@ +require([ + 'codecompass/model', + 'codecompass/viewHandler', + 'codecompass/util'], +function (model, viewHandler, util) { + + model.addService('csharpservice', 'CsharpService', LanguageServiceClient); + + function createTagLabels(tags) { + var label = ''; + + if (!tags) + return label; + + if (tags.indexOf('static') > -1) + label += 'S'; + if (tags.indexOf('constructor') > -1) + label += 'C'; + if (tags.indexOf('destructor') > -1) + label += 'D'; + if (tags.indexOf('implicit') > -1) + label += 'I'; + if (tags.indexOf('inherited') > -1) + label += 'I'; + if (tags.indexOf('virtual') > -1) + label += 'V'; + if (tags.indexOf('global') > -1) + label += 'G'; + + return label; + } + + function createReferenceCountLabel(label, count) { + return label + '(' + count + ')'; + } + + function createLabel(astNodeInfo) { + var labelClass = ''; + + if (astNodeInfo.tags.indexOf('implicit') > -1) + labelClass = 'label-implicit'; + + var labelValue = astNodeInfo.astNodeValue; + + // Create dom node for return type of a function and place it at the end of + // signature. + if (astNodeInfo.symbolType === 'Function') { + var init = labelValue.slice(0, labelValue.indexOf('(')); + var returnTypeEnd = init.lastIndexOf(' '); + + //--- Constructor, destructor doesn't have return type ---// + + if (returnTypeEnd !== -1) { + var funcSignature = init.slice(returnTypeEnd); + + labelValue = funcSignature + + ' : ' + + init.slice(0, returnTypeEnd) + + ""; + } + } + + var label = createTagLabels(astNodeInfo.tags) + + '' + + astNodeInfo.range.range.startpos.line + ':' + + astNodeInfo.range.range.startpos.column + ': ' + + labelValue + + ''; + + return label; + } + + function getCssClass(astNodeInfo) { + var tags = astNodeInfo.tags; + + return tags.indexOf('Public') > -1 ? 'icon-visibility icon-public' : + tags.indexOf('Private') > -1 ? 'icon-visibility icon-private' : + tags.indexOf('Protected') > -1 ? 'icon-visibility icon-protected' : + null; + } + + function groupReferencesByVisibilities(references, parentNode, nodeInfo) { + var res = []; + var visibilities = ['public', 'private', 'protected']; + + visibilities.forEach(function (visibility) { + var nodes = references.filter(function (reference) { + return reference.tags.indexOf(visibility) > -1; + }); + + if (!nodes.length) + return; + + res.push({ + id : nodeInfo.id + visibility + parentNode.refType, + name : createReferenceCountLabel(visibility, nodes.length), + refType : parentNode.refType, + hasChildren : true, + cssClass : 'icon-visibility icon-' + visibility, + getChildren : function () { + var res = []; + + nodes.forEach(function (reference) { + res.push({ + id : visibility + reference.id, + name : createLabel(reference), + refType : parentNode.refType, + nodeInfo : reference, + hasChildren : false, + cssClass : getCssClass(reference) + }); + }); + + return res; + } + }); + }); + + return res; + } + + function loadReferenceNodes(parentNode, nodeInfo, refTypes) { + var res = []; + var fileGroupsId = []; + + var references = model.csharpservice.getReferences( + nodeInfo.id, + parentNode.refType); + + if (parentNode.refType === refTypes['Method'] || + parentNode.refType === refTypes['Data member']) + return groupReferencesByVisibilities(references, parentNode, nodeInfo); + + references.forEach(function (reference) { + if (parentNode.refType === refTypes['Caller'] || + parentNode.refType === refTypes['Usage']) { + + //--- Group nodes by file name ---// + + var fileId = reference.range.file; + if (fileGroupsId[fileId]) + return; + + fileGroupsId[fileId] = parentNode.refType + fileId + reference.id; + + var referenceInFile = references.filter(function (reference) { + return reference.range.file === fileId; + }); + + var fileInfo = model.project.getFileInfo(fileId); + res.push({ + id : fileGroupsId[fileId], + name : createReferenceCountLabel( + fileInfo.name, referenceInFile.length), + refType : parentNode.refType, + hasChildren : true, + cssClass : util.getIconClass(fileInfo.path), + getChildren : function () { + var that = this; + var res = []; + + referenceInFile.forEach(function (reference) { + if (parentNode.refType === refTypes['Caller']) { + res.push({ + id : reference.id, + name : createLabel(reference), + nodeInfo : reference, + refType : parentNode.refType, + cssClass : 'icon icon-Method', + hasChildren : true, + getChildren : function () { + var res = []; + + //--- Recursive Node ---// + + var refCount = model.csharpservice.getReferenceCount( + reference.id, parentNode.refType); + + if (refCount) + res.push({ + id : 'Caller-' + reference.id, + name : createReferenceCountLabel( + parentNode.name, refCount), + nodeInfo : reference, + refType : parentNode.refType, + cssClass : parentNode.cssClass, + hasChildren : true, + getChildren : parentNode.getChildren + }); + + //--- Call ---// + + var calls = model.csharpservice.getReferences( + this.nodeInfo.id, + refTypes['This calls']); + + calls.forEach(function (call) { + if (call.entityHash === nodeInfo.entityHash) + res.push({ + name : createLabel(call), + refType : parentNode.refType, + nodeInfo : call, + hasChildren : false, + cssClass : getCssClass(call) + }); + }); + return res; + } + }); + } else if (parentNode.refType === refTypes['Usage']) { + res.push({ + id : fileGroupsId[fileId] + reference.id, + name : createLabel(reference), + refType : parentNode.refType, + nodeInfo : reference, + hasChildren : false, + cssClass : getCssClass(reference) + }); + } + }); + return res; + } + }); + } else { + res.push({ + name : createLabel(reference), + refType : parentNode.refType, + nodeInfo : reference, + hasChildren : false, + cssClass : getCssClass(reference) + }); + } + }); + + return res; + } + + /** + * This function returns file references children. + * @param parentNode Reference type node in Info Tree. + */ + function loadFileReferenceNodes(parentNode) { + var res = []; + + var references = model.csharpservice.getFileReferences( + parentNode.nodeInfo.id, + parentNode.refType); + + references.forEach(function (reference) { + res.push({ + name : createLabel(reference), + refType : parentNode.refType, + nodeInfo : reference, + hasChildren : false, + cssClass : getCssClass(reference) + }); + }); + + return res; + } + + function createRootNode(elementInfo) { + var rootLabel + = '' + + (elementInfo instanceof AstNodeInfo + ? elementInfo.symbolType + : 'File') + + ''; + + var rootValue + = '' + + (elementInfo instanceof AstNodeInfo + ? elementInfo.astNodeValue + : elementInfo.name) + + ''; + + var label = createTagLabels(elementInfo.tags) + + '' + + rootLabel + ': ' + rootValue + + ''; + + return { + id : 'root', + name : label, + cssClass : 'icon-info', + hasChildren : true, + getChildren : function () { + return that._store.query({ parent : 'root' }); + } + }; + } + + var csharpInfoTree = { + id : 'csharp-infotree', + render : function (elementInfo) { + var ret = []; + + ret.push(createRootNode(elementInfo)); + + if (elementInfo instanceof AstNodeInfo) { + //--- Properties ---// + + var props = model.csharpservice.getProperties(elementInfo.id); + + for (var propName in props) { + var propId = propName.replace(/ /g, '-'); + var label + = '' + propName + ': ' + + '' + props[propName] + ''; + + ret.push({ + name : label, + parent : 'root', + nodeInfo : elementInfo, + cssClass : 'icon-' + propId, + hasChildren : false + }); + } + + //--- References ---// + + var refTypes = model.csharpservice.getReferenceTypes(elementInfo.id); + for (var refType in refTypes) { + var refCount = + model.csharpservice.getReferenceCount(elementInfo.id, refTypes[refType]); + + if (refCount) + ret.push({ + name : createReferenceCountLabel(refType, refCount), + parent : 'root', + refType : refTypes[refType], + cssClass : 'icon-' + refType.replace(/ /g, '-'), + hasChildren : true, + getChildren : function () { + return loadReferenceNodes(this, elementInfo, refTypes); + } + }); + }; + + } else if (elementInfo instanceof FileInfo) { + + //--- File references ---// + + var refTypes = model.csharpservice.getFileReferenceTypes(elementInfo.id); + for (var refType in refTypes) { + var refCount = model.csharpservice.getFileReferenceCount( + elementInfo.id, refTypes[refType]); + + if (refCount) + ret.push({ + name : createReferenceCountLabel(refType, refCount), + parent : 'root', + nodeInfo : elementInfo, + refType : refTypes[refType], + cssClass : 'icon-' + refType.replace(/ /g, '-'), + hasChildren : true, + getChildren : function () { + return loadFileReferenceNodes(this); + } + }); + }; + + } + + return ret; + } + }; + + viewHandler.registerModule(csharpInfoTree, { + type : viewHandler.moduleType.InfoTree, + service : model.csharpservice + }); +}); diff --git a/plugins/csharp/webgui/js/csharpMenu.js b/plugins/csharp/webgui/js/csharpMenu.js new file mode 100644 index 000000000..bd95aca1b --- /dev/null +++ b/plugins/csharp/webgui/js/csharpMenu.js @@ -0,0 +1,151 @@ +require([ + 'dojo/topic', + 'dijit/Menu', + 'dijit/MenuItem', + 'dijit/PopupMenuItem', + 'codecompass/astHelper', + 'codecompass/model', + 'codecompass/urlHandler', + 'codecompass/viewHandler'], +function (topic, Menu, MenuItem, PopupMenuItem, astHelper, model, urlHandler, viewHandler) { + + model.addService('csharpservice', 'CsharpService', LanguageServiceClient); + + var getdefintion = { + id : 'csharp-text-getdefintion', + render : function (nodeInfo, fileInfo) { + return new MenuItem({ + label : 'Jump to definition', + accelKey : 'ctrl - click', + onClick : function () { + if (!nodeInfo || !fileInfo) + return; + + var languageService = model.getLanguageService(fileInfo.type); + astHelper.jumpToDef(nodeInfo.id, model.csharpservice); + + if (window.gtag) { + window.gtag ('event', 'jump_to_def', { + 'event_category' : urlHandler.getState('wsid'), + 'event_label' : urlHandler.getFileInfo().name + + ': ' + + nodeInfo.astNodeValue + }); + } + } + }); + } + }; + + viewHandler.registerModule(getdefintion, { + type : viewHandler.moduleType.TextContextMenu, + service : model.csharpservice + }); + + var infoTree = { + id : 'csharp-text-infotree', + render : function (nodeInfo, fileInfo) { + return new MenuItem({ + label : 'Info Tree', + onClick : function () { + if (!nodeInfo || !fileInfo) + return; + + topic.publish('codecompass/infotree', { + fileType : fileInfo.type, + elementInfo : nodeInfo + }); + + if (window.gtag) { + window.gtag ('event', 'info_tree', { + 'event_category' : urlHandler.getState('wsid'), + 'event_label' : urlHandler.getFileInfo().name + + ': ' + + nodeInfo.astNodeValue + }); + } + } + }); + } + }; + + viewHandler.registerModule(infoTree, { + type : viewHandler.moduleType.TextContextMenu, + service : model.csharpservice + }); + + var infobox = { + id : 'csharp-text-infobox', + render : function (nodeInfo, fileInfo) { + return new MenuItem({ + label : 'Documentation', + onClick : function () { + topic.publish('codecompass/documentation', { + fileType : fileInfo.type, + elementInfo : nodeInfo + }); + + if (window.gtag) { + window.gtag ('event', 'documentation', { + 'event_category' : urlHandler.getState('wsid'), + 'event_label' : urlHandler.getFileInfo().name + + ': ' + + nodeInfo.astNodeValue + }); + } + } + }); + } + }; + + viewHandler.registerModule(infobox, { + type : viewHandler.moduleType.TextContextMenu, + service : model.csharpservice + }); + + var diagrams = { + id : 'csharp-text-diagrams', + render : function (nodeInfo, fileInfo) { + if (!nodeInfo || !fileInfo) + return; + + var submenu = new Menu(); + + var diagramTypes = model.csharpservice.getDiagramTypes(nodeInfo.id); + for (diagramType in diagramTypes) + submenu.addChild(new MenuItem({ + label : diagramType, + type : diagramType, + onClick : function () { + var that = this; + + topic.publish('codecompass/openDiagram', { + handler : 'csharp-ast-diagram', + diagramType : diagramTypes[that.type], + node : nodeInfo.id + }); + } + })); + + submenu.addChild(new MenuItem({ + label : "CodeBites", + onClick : function () { + topic.publish('codecompass/codebites', { + node : nodeInfo + }); + } + })); + + if (Object.keys(diagramTypes).length !== 0) + return new PopupMenuItem({ + label : 'Diagrams', + popup : submenu + }); + } + }; + + viewHandler.registerModule(diagrams, { + type : viewHandler.moduleType.TextContextMenu, + service : model.csharpservice + }); +}); diff --git a/service/language/CMakeLists.txt b/service/language/CMakeLists.txt index 522038ec6..568fda00b 100644 --- a/service/language/CMakeLists.txt +++ b/service/language/CMakeLists.txt @@ -12,8 +12,9 @@ add_custom_command( ${CMAKE_CURRENT_BINARY_DIR}/gen-cpp/LanguageService.h ${CMAKE_CURRENT_BINARY_DIR}/gen-cpp ${CMAKE_CURRENT_BINARY_DIR}/gen-js + ${CMAKE_CURRENT_BINARY_DIR}/gen-netstd COMMAND - ${THRIFT_EXECUTABLE} --gen cpp --gen js + ${THRIFT_EXECUTABLE} --gen cpp --gen js --gen netstd -o ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/language.thrift DEPENDS diff --git a/service/language/language.thrift b/service/language/language.thrift index 91591abe8..6fc79d267 100644 --- a/service/language/language.thrift +++ b/service/language/language.thrift @@ -2,6 +2,7 @@ include "../project/common.thrift" include "../project/project.thrift" namespace cpp cc.service.language +namespace netstd language struct AstNodeInfo {