未验证 提交 320ca995 编写于 作者: P Phodal Huang

feat: add a basic bad smell examples

上级 61ac3a93
package call
import (
"fmt"
"github.com/antlr/antlr4/runtime/Go/antlr"
"os"
"path/filepath"
"strings"
. "github.com/phodal/coca/adapter/models"
. "github.com/phodal/coca/language/java"
)
var nodeInfos []JClassNode
type BadSmellModel struct {
File string
Line string
Bs string
}
type BadSmellApp struct {
}
func (j *BadSmellApp) AnalysisPath(codeDir string) []BadSmellModel {
nodeInfos = nil
files := (*BadSmellApp)(nil).javaFiles(codeDir)
for index := range files {
nodeInfo := NewClassNode()
file := files[index]
displayName := filepath.Base(file)
fmt.Println("Start parse java call: " + displayName)
parser := (*BadSmellApp)(nil).processFile(file)
context := parser.CompilationUnit()
listener := NewBadSmellListener()
antlr.NewParseTreeWalker().Walk(listener, context)
nodeInfo = listener.getNodeInfo()
nodeInfo.Path = file
nodeInfos = append(nodeInfos, *nodeInfo)
}
bsList := analysisBadSmell(nodeInfos)
return bsList
}
func analysisBadSmell(nodes []JClassNode) []BadSmellModel {
var badSmellList []BadSmellModel
for _, node := range nodes {
for _, method := range node.Methods {
if method.StartLine - method.StopLine > 50 {
longMethod := &BadSmellModel{node.Path, string(method.StartLine), "longMethod"}
badSmellList = append(badSmellList, *longMethod)
}
}
}
return badSmellList;
return nil
}
func (j *BadSmellApp) javaFiles(codeDir string) []string {
files := make([]string, 0)
_ = filepath.Walk(codeDir, func(path string, fi os.FileInfo, err error) error {
if strings.HasSuffix(path, ".java") && !strings.Contains(path, "Test.java") {
files = append(files, path)
}
return nil
})
return files
}
func (j *BadSmellApp) processFile(path string) *JavaParser {
is, _ := antlr.NewFileStream(path)
lexer := NewJavaLexer(is)
stream := antlr.NewCommonTokenStream(lexer, 0);
parser := NewJavaParser(stream)
return parser
}
package call
import (
"github.com/antlr/antlr4/runtime/Go/antlr"
. "github.com/phodal/coca/adapter/models"
. "github.com/phodal/coca/language/java"
"reflect"
"strings"
)
var imports []string
var clzs []string
var currentPkg string
var currentClz string
var methods []JMethod
var methodCalls []JMethodCall
var currentType string
var fields = make(map[string]string)
var localVars = make(map[string]string)
var formalParameters = make(map[string]string)
func NewBadSmellListener() *BadSmellListener {
currentClz = ""
currentPkg = ""
methods = nil
methodCalls = nil
return &BadSmellListener{}
}
type BadSmellListener struct {
BaseJavaParserListener
}
func (s *BadSmellListener) getNodeInfo() *JClassNode {
return &JClassNode{currentPkg, currentClz, currentType, "", methods, methodCalls}
}
func (s *BadSmellListener) EnterPackageDeclaration(ctx *PackageDeclarationContext) {
currentPkg = ctx.QualifiedName().GetText()
}
func (s *BadSmellListener) EnterImportDeclaration(ctx *ImportDeclarationContext) {
importText := ctx.QualifiedName().GetText()
imports = append(imports, importText)
}
func (s *BadSmellListener) EnterClassDeclaration(ctx *ClassDeclarationContext) {
currentType = "Class"
currentClz = ctx.IDENTIFIER().GetText()
}
func (s *BadSmellListener) EnterInterfaceDeclaration(ctx *InterfaceDeclarationContext) {
currentType = "Interface"
currentClz = ctx.IDENTIFIER().GetText()
}
func (s *BadSmellListener) EnterInterfaceMethodDeclaration(ctx *InterfaceMethodDeclarationContext) {
startLine := ctx.GetStart().GetLine()
startLinePosition := ctx.IDENTIFIER().GetSymbol().GetColumn()
stopLine := ctx.GetStop().GetLine()
name := ctx.IDENTIFIER().GetText()
stopLinePosition := startLinePosition + len(name)
typeType := ctx.TypeTypeOrVoid().GetText()
method := &JMethod{name, typeType, startLine, startLinePosition, stopLine, stopLinePosition}
methods = append(methods, *method)
}
func (s *BadSmellListener) EnterFormalParameter(ctx *FormalParameterContext) {
formalParameters[ctx.VariableDeclaratorId().GetText()] = ctx.TypeType().GetText()
}
func (s *BadSmellListener) EnterFieldDeclaration(ctx *FieldDeclarationContext) {
declarators := ctx.VariableDeclarators()
variableName := declarators.GetParent().GetChild(0).(antlr.ParseTree).GetText()
fields[variableName] = ctx.TypeType().GetText()
}
func (s *BadSmellListener) EnterLocalVariableDeclaration(ctx *LocalVariableDeclarationContext) {
typ := ctx.GetChild(0).(antlr.ParseTree).GetText()
variableName := ctx.GetChild(1).GetChild(0).GetChild(0).(antlr.ParseTree).GetText()
localVars[variableName] = typ
}
func (s *BadSmellListener) EnterMethodDeclaration(ctx *MethodDeclarationContext) {
startLine := ctx.GetStart().GetLine()
startLinePosition := ctx.IDENTIFIER().GetSymbol().GetColumn()
stopLine := ctx.GetStop().GetLine()
name := ctx.IDENTIFIER().GetText()
stopLinePosition := startLinePosition + len(name)
//XXX: find the start position of {, not public
typeType := ctx.TypeTypeOrVoid().GetText()
method := &JMethod{name, typeType, startLine, startLinePosition, stopLine, stopLinePosition}
methods = append(methods, *method)
}
func (s *BadSmellListener) EnterMethodCall(ctx *MethodCallContext) {
var targetCtx = ctx.GetParent().GetChild(0).(antlr.ParseTree).GetText()
var targetType = parseTargetType(targetCtx)
callee := ctx.GetChild(0).(antlr.ParseTree).GetText()
startLine := ctx.GetStart().GetLine()
startLinePosition := ctx.GetStart().GetColumn()
stopLine := ctx.GetStop().GetLine()
stopLinePosition := startLinePosition + len(callee)
//typeType := ctx.GetChild(0).(antlr.ParseTree).TypeTypeOrVoid().GetText()
fullType := warpTargetFullType(targetType)
if fullType != "" {
jMethodCall := &JMethodCall{removeTarget(fullType), "", targetType, callee, startLine, startLinePosition, stopLine, stopLinePosition}
methodCalls = append(methodCalls, *jMethodCall)
} else {
if ctx.GetText() == targetType {
methodName := ctx.IDENTIFIER().GetText()
jMethodCall := &JMethodCall{currentPkg, "",currentClz, methodName, startLine, startLinePosition, stopLine, stopLinePosition}
methodCalls = append(methodCalls, *jMethodCall)
}
}
}
func (s *BadSmellListener) EnterExpression(ctx *ExpressionContext) {
// lambda BlogPO::of
if ctx.COLONCOLON() != nil {
text := ctx.Expression(0).GetText()
methodName := ctx.IDENTIFIER().GetText()
targetType := parseTargetType(text)
fullType := warpTargetFullType(targetType)
startLine := ctx.GetStart().GetLine()
startLinePosition := ctx.GetStart().GetColumn()
stopLine := ctx.GetStop().GetLine()
stopLinePosition := startLinePosition + len(text)
jMethodCall := &JMethodCall{removeTarget(fullType), "", targetType, methodName, startLine, startLinePosition, stopLine, stopLinePosition}
methodCalls = append(methodCalls, *jMethodCall)
}
}
func (s *BadSmellListener) appendClasses(classes []string) {
clzs = classes
}
func removeTarget(fullType string) string {
split := strings.Split(fullType, ".")
return strings.Join(split[:len(split)-1], ".")
}
func parseTargetType(targetCtx string) string {
targetVar := targetCtx
targetType := targetVar
//TODO: update this reflect
typeOf := reflect.TypeOf(targetCtx).String()
if strings.HasSuffix(typeOf, "MethodCallContext") {
targetType = currentClz;
} else {
fieldType := fields[targetVar]
formalType := formalParameters[targetVar]
localVarType := localVars[targetVar]
if fieldType != "" {
targetType = fieldType
} else if formalType != "" {
targetType = formalType;
} else if localVarType != "" {
targetType = localVarType;
}
}
return targetType
}
func warpTargetFullType(targetType string) string {
if strings.EqualFold(currentClz, targetType) {
return currentPkg + "." + targetType
}
for index := range imports {
imp := imports[index]
if strings.HasSuffix(imp, targetType) {
return imp
}
}
//maybe the same package
for _, clz := range clzs {
if strings.HasSuffix(clz, "." + targetType) {
return clz
}
}
//1. current package, 2. import by *
return ""
}
package bs
import (
"encoding/json"
"fmt"
. "github.com/phodal/coca/adapter/models"
. "github.com/phodal/coca/refactor/base/models"
. "github.com/phodal/coca/utils"
)
var nodes []JMoveStruct
type BadSmellApp struct {
}
var depsFile string
var parsedDeps []JClassNode
func NewBadSmellApp(depPath string) *BadSmellApp {
depsFile = depPath
return &BadSmellApp{}
}
func (j *BadSmellApp) Start() {
file := ReadFile(depsFile)
if file == nil {
return
}
_ = json.Unmarshal(file, &parsedDeps)
fmt.Println(parsedDeps)
}
package cmd
import (
. "github.com/phodal/coca/bs"
"encoding/json"
"github.com/spf13/cobra"
. "github.com/phodal/coca/bs"
. "github.com/phodal/coca/utils"
)
var badsmellCmd *cobra.Command = &cobra.Command{
Use: "badsmell",
Short: "badsmell recognized",
Short: "Bad Code Smell",
Long: ``,
Run: func(cmd *cobra.Command, args []string) {
depFile := cmd.Flag("dependence").Value.String()
importPath := cmd.Flag("path").Value.String()
if importPath != "" {
bsApp := new(BadSmellApp)
bsList := bsApp.AnalysisPath(importPath)
bsModel, _ := json.MarshalIndent(bsList, "", "\t")
if depFile != "" {
bsApp := NewBadSmellApp(depFile)
bsApp.Start()
WriteToFile("deps.json", string(bsModel))
}
},
}
......@@ -22,5 +29,5 @@ var badsmellCmd *cobra.Command = &cobra.Command{
func init() {
rootCmd.AddCommand(badsmellCmd)
badsmellCmd.PersistentFlags().StringP("dependence", "d", "", "dependence path")
badsmellCmd.PersistentFlags().StringP("path", "p", "Code Path", "example -p src/main")
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册