From 4bd7306da4b0af34fe78b8e06adfb56a17a506b5 Mon Sep 17 00:00:00 2001 From: Phodal Huang Date: Thu, 3 Mar 2022 20:13:46 +0800 Subject: [PATCH] feat: add method annotation support --- .../chapi/ast/csharpast/CSharpAnalyser.kt | 14 +++-- .../ast/csharpast/CSharpFullIdentListener.kt | 53 +++++++++++++++++-- .../csharpast/CSharpFullIdentListenerTest.kt | 49 +++++++++++++++++ 3 files changed, 103 insertions(+), 13 deletions(-) diff --git a/chapi-ast-csharp/src/main/kotlin/chapi/ast/csharpast/CSharpAnalyser.kt b/chapi-ast-csharp/src/main/kotlin/chapi/ast/csharpast/CSharpAnalyser.kt index 52581d24..ca3fa356 100644 --- a/chapi-ast-csharp/src/main/kotlin/chapi/ast/csharpast/CSharpAnalyser.kt +++ b/chapi-ast-csharp/src/main/kotlin/chapi/ast/csharpast/CSharpAnalyser.kt @@ -14,14 +14,12 @@ open class CSharpAnalyser { ParseTreeWalker().walk(listener, context) - val nodeInfo = listener.getNodeInfo() - return nodeInfo + return listener.getNodeInfo() } - open fun parse(str: String): CSharpParser { - val fromString = CharStreams.fromString(str) - val lexer = CSharpLexer (fromString) - val tokenStream = CommonTokenStream(lexer) - return CSharpParser(tokenStream) - } + private fun parse(str: String): CSharpParser = + CharStreams.fromString(str) + .let(::CSharpLexer) + .let(::CommonTokenStream) + .let(::CSharpParser) } diff --git a/chapi-ast-csharp/src/main/kotlin/chapi/ast/csharpast/CSharpFullIdentListener.kt b/chapi-ast-csharp/src/main/kotlin/chapi/ast/csharpast/CSharpFullIdentListener.kt index 1e004515..e95fe4b0 100644 --- a/chapi-ast-csharp/src/main/kotlin/chapi/ast/csharpast/CSharpFullIdentListener.kt +++ b/chapi-ast-csharp/src/main/kotlin/chapi/ast/csharpast/CSharpFullIdentListener.kt @@ -1,11 +1,13 @@ package chapi.ast.csharpast import chapi.ast.antlr.CSharpParser +import chapi.ast.antlr.CSharpParser.Class_typeContext import chapi.ast.antlr.CSharpParser.Type_declarationContext import chapi.domain.core.* import chapi.infra.Stack class CSharpFullIdentListener(val fileName: String) : CSharpAstListener() { + private var currentStruct: CodeDataStruct = CodeDataStruct(); private var codeContainer: CodeContainer = CodeContainer(FullName = fileName) private var currentContainer: CodeContainer = codeContainer private var containerStack: Stack = Stack() @@ -67,12 +69,10 @@ class CSharpFullIdentListener(val fileName: String) : CSharpAstListener() { val lastContainer = containerStack.elements.last() lastContainer.Containers += currentContainer containerStack.elements[containerStack.elements.size - 1] = lastContainer - containerStack.push(currentContainer) } else { codeContainer.Containers += currentContainer containerStack.push(currentContainer) - println(containerStack.elements.size) } } @@ -88,8 +88,8 @@ class CSharpFullIdentListener(val fileName: String) : CSharpAstListener() { val classMemberDeclarations = ctx.class_body().class_member_declarations() if (classMemberDeclarations != null) { - for (classMemberDeclarationcontext in classMemberDeclarations.class_member_declaration()) { - this.handleClassMember(classMemberDeclarationcontext, codeDataStruct) + for (classMemberDecl in classMemberDeclarations.class_member_declaration()) { + this.handleClassMember(classMemberDecl, codeDataStruct) } } @@ -101,7 +101,50 @@ class CSharpFullIdentListener(val fileName: String) : CSharpAstListener() { } } - currentContainer.DataStructures += codeDataStruct + currentStruct = codeDataStruct; + } + + override fun exitClass_definition(ctx: CSharpParser.Class_definitionContext?) { + currentContainer.DataStructures += currentStruct + } + + override fun enterProperty_declaration(ctx: CSharpParser.Property_declarationContext?) { + val memberName = ctx!!.member_name() + when (ctx.parent.javaClass.simpleName) { + "Typed_member_declarationContext" -> { + val typedMember = ctx.parent as CSharpParser.Typed_member_declarationContext + val typeValue = memberName.text + val typeContext = typedMember.type_() + + val field = createField(typeValue, typeContext) + + currentStruct.Fields += field + } + } + } + + private fun createField(typeValue: String, typeContext: CSharpParser.Type_Context): CodeField { + val field = CodeField(TypeValue = typeValue) + field.TypeType = typeContext.text + + val child = typeContext.base_type().getChild(0) + when (child.javaClass.simpleName) { + "Class_typeContext" -> { + val clazzType = child as Class_typeContext + val nsOrType = clazzType.namespace_or_type_name() + if (nsOrType != null) { + field.Modifiers = arrayOf(nsOrType.identifier()[0].text) + if (nsOrType.type_argument_list() != null) { + nsOrType.type_argument_list() + .asSequence() + .flatMap { it.type_().asSequence() } + .forEach { field.TypeType = it.text } + } + } + } + } + + return field } private fun parseAnnotations(attributes: CSharpParser.AttributesContext?): Array { diff --git a/chapi-ast-csharp/src/test/kotlin/chapi/ast/csharpast/CSharpFullIdentListenerTest.kt b/chapi-ast-csharp/src/test/kotlin/chapi/ast/csharpast/CSharpFullIdentListenerTest.kt index b67dcafb..d163d48e 100644 --- a/chapi-ast-csharp/src/test/kotlin/chapi/ast/csharpast/CSharpFullIdentListenerTest.kt +++ b/chapi-ast-csharp/src/test/kotlin/chapi/ast/csharpast/CSharpFullIdentListenerTest.kt @@ -221,4 +221,53 @@ namespace Chapi { assertEquals(2, structs[0].Functions.size) } + + @Test + fun shouldIdentProperty() { + val code = """ +using System; + +namespace Chapi { + public class Chapi { + public Chapi() {} + public Chapi(long id) {} + + public long ChapiId { get; set; } + } +} +""" + val codeContainer = CSharpAnalyser().analysis(code, "ChapiController.cs") + val structs = codeContainer.Containers[0].DataStructures + assertEquals(structs.size, 1) + + assertEquals(2, structs[0].Functions.size) + assertEquals(1, structs[0].Fields.size) + assertEquals("long", structs[0].Fields[0].TypeType) + assertEquals("ChapiId", structs[0].Fields[0].TypeValue) + } + + @Test + fun shouldIdentPropertyInList() { + val code = """ +using System; + +namespace Chapi { + public class Chapi { + public Chapi() {} + public Chapi(long id) {} + + public List Parameters { get; set; } + } +} +""" + val codeContainer = CSharpAnalyser().analysis(code, "ChapiController.cs") + val structs = codeContainer.Containers[0].DataStructures + assertEquals(structs.size, 1) + + assertEquals(2, structs[0].Functions.size) + assertEquals(1, structs[0].Fields.size) + assertEquals("List", structs[0].Fields[0].Modifiers[0]) + assertEquals("DeviceParameter", structs[0].Fields[0].TypeType) + assertEquals("Parameters", structs[0].Fields[0].TypeValue) + } }