feat: [cmd] add golang analysis api support

上级 2d5f6629
......@@ -3,13 +3,17 @@ package cmd
import (
"encoding/json"
"github.com/phodal/coca/cmd/cmd_util"
"github.com/phodal/coca/pkg/adapter/cocafile"
"github.com/phodal/coca/pkg/application/analysis"
"github.com/phodal/coca/pkg/domain/core_domain"
"github.com/phodal/coca/pkg/infrastructure/ast/cocago"
"github.com/spf13/cobra"
)
type AnalysisCmdConfig struct {
Path string
ForceUpdate bool
Lang string
}
var (
......@@ -21,31 +25,61 @@ var analysisCmd = &cobra.Command{
Short: "analysis code",
Long: ``,
Run: func(cmd *cobra.Command, args []string) {
importPath := analysisCmdConfig.Path
if analysisCmdConfig.Lang == "go" {
analysisGo()
} else {
analysisJava()
}
},
}
identifierApp := analysis.NewJavaIdentifierApp()
iNodes := identifierApp.AnalysisPath(importPath)
func analysisGo() {
importPath := analysisCmdConfig.Path
identModel, _ := json.MarshalIndent(iNodes, "", "\t")
cmd_util.WriteToCocaFile("identify.json", string(identModel))
var results []core_domain.CodeFile
files := cocafile.GetFilesWithFilter(importPath, cocafile.GoFileFilter)
for _, file := range files {
parser := cocago.NewCocagoParser()
parser.SetOutput(output)
result := parser.ProcessFile(file)
var classes []string = nil
results = append(results, result)
}
for _, node := range iNodes {
classes = append(classes, node.Package+"."+node.NodeName)
}
var ds []core_domain.CodeDataStruct
for _, result := range results {
ds = append(ds, result.DataStructures...)
}
callApp := analysis.NewJavaFullApp()
cModel, _ := json.MarshalIndent(ds, "", "\t")
cmd_util.WriteToCocaFile("godeps.json", string(cModel))
}
callNodes := callApp.AnalysisPath(importPath, classes, iNodes)
cModel, _ := json.MarshalIndent(callNodes, "", "\t")
cmd_util.WriteToCocaFile("deps.json", string(cModel))
},
func analysisJava() {
importPath := analysisCmdConfig.Path
identifierApp := analysis.NewJavaIdentifierApp()
iNodes := identifierApp.AnalysisPath(importPath)
identModel, _ := json.MarshalIndent(iNodes, "", "\t")
cmd_util.WriteToCocaFile("identify.json", string(identModel))
var classes []string = nil
for _, node := range iNodes {
classes = append(classes, node.Package+"."+node.NodeName)
}
callApp := analysis.NewJavaFullApp()
callNodes := callApp.AnalysisPath(importPath, classes, iNodes)
cModel, _ := json.MarshalIndent(callNodes, "", "\t")
cmd_util.WriteToCocaFile("deps.json", string(cModel))
}
func init() {
rootCmd.AddCommand(analysisCmd)
analysisCmd.PersistentFlags().StringVarP(&analysisCmdConfig.Path, "path", "p", ".", "example -p core/main")
analysisCmd.PersistentFlags().StringVarP(&analysisCmdConfig.Lang, "lang", "l", "java", "coca analysis -l java")
analysisCmd.PersistentFlags().BoolVarP(&analysisCmdConfig.ForceUpdate, "force", "f", false, "force update -f")
}
package cmd
import (
"github.com/phodal/coca/cocatest/testcase"
"testing"
)
func Test_Analysis_Go(t *testing.T) {
path := "config"
analysis := []testcase.CmdTestCase{{
Name: "analysis",
Cmd: "analysis -f -l go -p " + path,
Golden: "testdata/analysis_go.txt",
}}
RunTestCmd(t, analysis)
}
......@@ -10,7 +10,7 @@ func TestApi(t *testing.T) {
analysis := []testcase.CmdTestCase{{
Name: "analysis",
Cmd: "analysis -p " + path,
Cmd: "analysis -l java -p " + path,
Golden: "",
}}
RunTestCmd(t, analysis)
......
process file config/cmd_config.go
......@@ -30,7 +30,6 @@ func buildMethodsFromDeps(clzs []core_domain.CodeDataStruct) string_helper.PairL
}
words := SegmentConceptCamelcase(methodsName)
words = removeNormalWords(words)
wordCounts := string_helper.RankByWordCount(words)
......
package goapp
import (
"bytes"
"github.com/phodal/coca/pkg/adapter/cocafile"
"github.com/phodal/coca/pkg/domain/core_domain"
"github.com/phodal/coca/pkg/infrastructure/ast/cocago"
......@@ -16,7 +17,8 @@ func ProcessPackage(path string, debug bool) []*core_domain.CodeFile {
filesData := make([]*core_domain.CodeFile, len(files))
parser := cocago.NewCocagoParser()
if debug {
parser.SetOutput(true)
buf := new(bytes.Buffer)
parser.SetOutput(buf)
}
for i, file := range files {
processFile := parser.ProcessFile(file)
......
package cocago
import (
"bytes"
"fmt"
"github.com/phodal/coca/pkg/domain/core_domain"
"go/ast"
......@@ -19,7 +18,6 @@ var currentPackage *core_domain.CodePackage
type CocagoParser struct {
}
var debug = false
var output io.Writer
func NewCocagoParser() *CocagoParser {
......@@ -28,10 +26,8 @@ func NewCocagoParser() *CocagoParser {
return &CocagoParser{}
}
func (n *CocagoParser) SetOutput(isDebug bool) io.Writer {
output = new(bytes.Buffer)
debug = isDebug
func (n *CocagoParser) SetOutput(out io.Writer) io.Writer {
output = out
return output
}
......@@ -56,6 +52,7 @@ func (n *CocagoParser) Visitor(f *ast.File, fset *token.FileSet, fileName string
var currentStruct core_domain.CodeDataStruct
var currentFile core_domain.CodeFile
var currentFunc *core_domain.CodeFunction
var dsMap = make(map[string]*core_domain.CodeDataStruct)
currentFile.FullName = fileName
var funcType = ""
......@@ -72,12 +69,17 @@ func (n *CocagoParser) Visitor(f *ast.File, fset *token.FileSet, fileName string
currentFile.Imports = append(currentFile.Imports, *imp)
case *ast.TypeSpec:
currentStruct = core_domain.CodeDataStruct{}
currentStruct.NodeName = x.Name.String()
currentStruct.NodeName = x.Name.Name
dsMap[currentStruct.NodeName] = &currentStruct
case *ast.StructType:
AddStructType(currentStruct, x, &currentFile)
fmt.Println(currentStruct.NodeName)
AddStructType(currentStruct.NodeName, x, &currentFile, dsMap)
case *ast.FuncDecl:
funcType = "FuncDecl"
currentFunc = AddFunctionDecl(currentStruct, x, &currentFile)
currentFunc, recv := AddFunctionDecl(x, &currentFile)
if recv != "" {
dsMap[recv].Functions = append(dsMap[recv].Functions, *currentFunc)
}
case *ast.FuncType:
if funcType != "FuncDecl" {
AddNestedFunction(currentFunc, x)
......@@ -85,15 +87,21 @@ func (n *CocagoParser) Visitor(f *ast.File, fset *token.FileSet, fileName string
funcType = ""
case *ast.InterfaceType:
AddInterface(x, lastIdent, &currentFile)
currentStruct := AddInterface(x, lastIdent, &currentFile)
dsMap[currentStruct.NodeName] = &currentStruct
default:
if reflect.TypeOf(x) != nil {
if reflect.TypeOf(x) != nil && reflect.TypeOf(output).String() != "*bytes.Buffer" {
fmt.Fprintf(output, "Visitor case %s\n", reflect.TypeOf(x))
}
}
return true
})
currentFile.DataStructures = nil
for _, ds := range dsMap {
currentFile.DataStructures = append(currentFile.DataStructures, *ds)
}
return &currentFile
}
......@@ -114,7 +122,7 @@ func BuildImport(x *ast.ImportSpec) *core_domain.CodeImport {
return imp
}
func AddInterface(x *ast.InterfaceType, ident string, codeFile *core_domain.CodeFile) {
func AddInterface(x *ast.InterfaceType, ident string, codeFile *core_domain.CodeFile) core_domain.CodeDataStruct {
properties := BuildFieldToProperty(x.Methods.List)
dataStruct := core_domain.CodeDataStruct{
......@@ -123,34 +131,27 @@ func AddInterface(x *ast.InterfaceType, ident string, codeFile *core_domain.Code
}
member := core_domain.CodeMember{
DataStructID: dataStruct.NodeName,
DataStructID: ident,
Type: "interface",
}
codeFile.Members = append(codeFile.Members, &member)
codeFile.DataStructures = append(codeFile.DataStructures, dataStruct)
return dataStruct
}
func AddNestedFunction(currentFunc *core_domain.CodeFunction, x *ast.FuncType) {
}
func AddFunctionDecl(currentStruct core_domain.CodeDataStruct, x *ast.FuncDecl, currentFile *core_domain.CodeFile) *core_domain.CodeFunction {
func AddFunctionDecl(x *ast.FuncDecl, currentFile *core_domain.CodeFile) (*core_domain.CodeFunction, string) {
recv := ""
if x.Recv != nil {
recv = BuildReceiver(x, recv)
}
codeFunc := BuildFunction(x)
if recv != "" {
member := GetMemberFromFile(*currentFile, recv)
if member != nil {
member.FunctionNodes = append(member.FunctionNodes, *codeFunc)
} else {
createMember(currentStruct)
// todo
}
} else {
if recv == "" {
member := GetMemberFromFile(*currentFile, "default")
if member == nil {
member = &core_domain.CodeMember{
......@@ -163,7 +164,7 @@ func AddFunctionDecl(currentStruct core_domain.CodeDataStruct, x *ast.FuncDecl,
currentFile.Members = append(currentFile.Members, member)
}
return codeFunc
return codeFunc, recv
}
func BuildReceiver(x *ast.FuncDecl, recv string) string {
......@@ -260,16 +261,16 @@ func getFieldName(field *ast.Field) string {
return field.Names[0].Name
}
func AddStructType(currentStruct core_domain.CodeDataStruct, x *ast.StructType, currentFile *core_domain.CodeFile) {
func AddStructType(currentNodeName string, x *ast.StructType, currentFile *core_domain.CodeFile, dsMap map[string]*core_domain.CodeDataStruct) {
member := core_domain.CodeMember{
DataStructID: currentStruct.NodeName,
DataStructID: currentNodeName,
Type: "struct",
}
for _, field := range x.Fields.List {
property := BuildPropertyField(getFieldName(field), field)
member.FileID = currentFile.FullName
currentStruct.InOutProperties = append(currentStruct.InOutProperties, *property)
dsMap[currentNodeName].InOutProperties = append(dsMap[currentNodeName].InOutProperties, *property)
}
currentFile.Members = append(currentFile.Members, &member)
currentFile.DataStructures = append(currentFile.DataStructures, currentStruct)
}
package cocago
import (
"bytes"
. "github.com/onsi/gomega"
"github.com/phodal/coca/cocatest"
"os"
......@@ -18,7 +19,8 @@ var testParser *CocagoParser
func setup() {
testParser = NewCocagoParser()
testParser.SetOutput(true)
buf := new(bytes.Buffer)
testParser.SetOutput(buf)
}
func shutdown() {
......
......@@ -7,24 +7,7 @@
"Fields": null,
"FilePath": "",
"FunctionCalls": null,
"Functions": null,
"Implements": null,
"Imports": null,
"InOutProperties": null,
"InnerStructures": null,
"MultipleExtend": null,
"NodeName": "O",
"Package": "",
"Type": ""
}
],
"FullName": "testdata/node_infos/struct_type_zero.code",
"Imports": null,
"Members": [
{
"DataStructID": "O",
"FileID": "",
"FunctionNodes": [
"Functions": [
{
"Annotations": null,
"Extension": null,
......@@ -47,6 +30,23 @@
"ReturnType": ""
}
],
"Implements": null,
"Imports": null,
"InOutProperties": null,
"InnerStructures": null,
"MultipleExtend": null,
"NodeName": "O",
"Package": "",
"Type": ""
}
],
"FullName": "testdata/node_infos/struct_type_zero.code",
"Imports": null,
"Members": [
{
"DataStructID": "O",
"FileID": "",
"FunctionNodes": null,
"ID": "",
"Name": "",
"Namespace": null,
......
......@@ -7,7 +7,52 @@
"Fields": null,
"FilePath": "",
"FunctionCalls": null,
"Functions": null,
"Functions": [
{
"Annotations": null,
"Extension": null,
"InnerFunctions": null,
"InnerStructures": null,
"IsConstructor": false,
"IsReturnNull": false,
"MethodCalls": [
{
"MethodName": "Println",
"NodeName": "fmt",
"Package": "",
"Parameters": [
{
"Modifiers": null,
"Name": "",
"Parameters": null,
"ReturnTypes": null,
"TypeType": "STRING",
"TypeValue": "\"Declared outside and invoked!!!\""
}
],
"Position": {
"StartLine": 0,
"StartLinePosition": 0,
"StopLine": 0,
"StopLinePosition": 0
},
"Type": ""
}
],
"Modifiers": null,
"MultipleReturns": null,
"Name": "outside",
"Override": false,
"Parameters": null,
"Position": {
"StartLine": 0,
"StartLinePosition": 0,
"StopLine": 0,
"StopLinePosition": 0
},
"ReturnType": ""
}
],
"Implements": null,
"Imports": null,
"InOutProperties": [
......@@ -57,52 +102,7 @@
{
"DataStructID": "person",
"FileID": "testdata/node_infos/struct_with_func_decl.code",
"FunctionNodes": [
{
"Annotations": null,
"Extension": null,
"InnerFunctions": null,
"InnerStructures": null,
"IsConstructor": false,
"IsReturnNull": false,
"MethodCalls": [
{
"MethodName": "Println",
"NodeName": "fmt",
"Package": "",
"Parameters": [
{
"Modifiers": null,
"Name": "",
"Parameters": null,
"ReturnTypes": null,
"TypeType": "STRING",
"TypeValue": "\"Declared outside and invoked!!!\""
}
],
"Position": {
"StartLine": 0,
"StartLinePosition": 0,
"StopLine": 0,
"StopLinePosition": 0
},
"Type": ""
}
],
"Modifiers": null,
"MultipleReturns": null,
"Name": "outside",
"Override": false,
"Parameters": null,
"Position": {
"StartLine": 0,
"StartLinePosition": 0,
"StopLine": 0,
"StopLinePosition": 0
},
"ReturnType": ""
}
],
"FunctionNodes": null,
"ID": "",
"Name": "",
"Namespace": null,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册