mirror of
https://github.com/Dvorinka/Devour.git
synced 2026-06-03 20:13:03 +00:00
updage
This commit is contained in:
@@ -268,7 +268,7 @@ type CouplingDetector struct {
|
||||
func NewCouplingDetector(finder quality.FileFinder) *CouplingDetector {
|
||||
return &CouplingDetector{
|
||||
BaseDetector: quality.NewBaseDetector("coupling", quality.SeverityT3, finder),
|
||||
maxFanOut: 10,
|
||||
maxFanOut: 20, // Increased from 10 to 20 for more realistic threshold
|
||||
}
|
||||
}
|
||||
|
||||
@@ -330,7 +330,11 @@ func (d *CouplingDetector) Detect(ctx context.Context, path string, config *qual
|
||||
|
||||
for pkg, importedBy := range pkgImportedBy {
|
||||
fanIn := len(importedBy)
|
||||
if fanIn > d.maxFanOut*2 {
|
||||
// Skip standard library packages from fan-in analysis
|
||||
if d.isStandardLibraryPackage(pkg) {
|
||||
continue
|
||||
}
|
||||
if fanIn > d.maxFanOut*3 { // Increased threshold for fan-in
|
||||
finding := quality.Finding{
|
||||
ID: fmt.Sprintf("coupling_fanin::%s", pkg),
|
||||
Type: "coupling",
|
||||
@@ -339,7 +343,7 @@ func (d *CouplingDetector) Detect(ctx context.Context, path string, config *qual
|
||||
File: pkg,
|
||||
Line: 1,
|
||||
Severity: quality.SeverityT2,
|
||||
Score: fanIn/5 - d.maxFanOut/5,
|
||||
Score: fanIn/10 - d.maxFanOut/10, // Reduced scoring
|
||||
Status: quality.StatusOpen,
|
||||
Metadata: map[string]string{
|
||||
"package": pkg,
|
||||
@@ -356,6 +360,21 @@ func (d *CouplingDetector) Detect(ctx context.Context, path string, config *qual
|
||||
return findings, nil
|
||||
}
|
||||
|
||||
func (d *CouplingDetector) isStandardLibraryPackage(pkgPath string) bool {
|
||||
// Standard library packages that commonly have high fan-in
|
||||
standardLibs := []string{
|
||||
"fmt", "time", "strings", "context", "os", "io", "net/http",
|
||||
"encoding/json", "path/filepath", "sync", "math", "regexp",
|
||||
}
|
||||
|
||||
for _, lib := range standardLibs {
|
||||
if strings.Contains(pkgPath, lib) && !strings.Contains(pkgPath, "github.com") {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (d *CouplingDetector) detectHubPackages(pkgImports, pkgImportedBy map[string][]string) []quality.Finding {
|
||||
var findings []quality.Finding
|
||||
|
||||
|
||||
@@ -30,6 +30,31 @@ func (d *DeadCodeDetector) Severity() quality.Severity {
|
||||
return quality.SeverityT2
|
||||
}
|
||||
|
||||
func (d *DeadCodeDetector) shouldSkipExport(name, objType string) bool {
|
||||
// Skip common API surface exports that might be used externally
|
||||
skipPatterns := []string{
|
||||
"Version", "License", "APIKey", "Config", "Options",
|
||||
"Client", "Server", "Handler", "Service", "Manager",
|
||||
"Store", "Cache", "Index", "Search", "Query",
|
||||
}
|
||||
|
||||
// Skip type definitions and constants
|
||||
if strings.Contains(objType, "type") ||
|
||||
strings.Contains(objType, "const") ||
|
||||
strings.Contains(objType, "var") {
|
||||
return true
|
||||
}
|
||||
|
||||
// Skip common naming patterns
|
||||
for _, pattern := range skipPatterns {
|
||||
if name == pattern {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (d *DeadCodeDetector) Detect(ctx context.Context, path string, config *quality.Config) ([]quality.Finding, error) {
|
||||
cfg := &packages.Config{
|
||||
Mode: packages.NeedName | packages.NeedTypes | packages.NeedTypesInfo | packages.NeedFiles,
|
||||
@@ -58,18 +83,24 @@ func (d *DeadCodeDetector) Detect(ctx context.Context, path string, config *qual
|
||||
continue
|
||||
}
|
||||
|
||||
// Skip unexported objects - they're internal
|
||||
if !obj.Exported() {
|
||||
continue
|
||||
}
|
||||
|
||||
key := obj.Pkg().Path() + "." + obj.Name()
|
||||
if !used[key] {
|
||||
// Skip certain types of exports that are commonly legitimate
|
||||
if d.shouldSkipExport(obj.Name(), obj.Type().String()) {
|
||||
continue
|
||||
}
|
||||
|
||||
pos := pkg.Fset.Position(obj.Pos())
|
||||
finding := quality.Finding{
|
||||
ID: fmt.Sprintf("dead_code::%s::%s", pos.Filename, obj.Name()),
|
||||
Type: "dead_code",
|
||||
Title: fmt.Sprintf("Unused exported identifier: %s", obj.Name()),
|
||||
Description: fmt.Sprintf("The exported %s '%s' is never used in the codebase. Consider removing it or documenting its intended use.", obj.Type(), obj.Name()),
|
||||
Description: fmt.Sprintf("The exported %s '%s' is never used in codebase. Consider removing it or documenting its intended use.", obj.Type(), obj.Name()),
|
||||
File: pos.Filename,
|
||||
Line: pos.Line,
|
||||
Severity: quality.SeverityT2,
|
||||
@@ -290,7 +321,6 @@ func (d *CycleDetector) findCycles(graph map[string][]string) [][]string {
|
||||
}
|
||||
}
|
||||
|
||||
path = path[:len(path)-1]
|
||||
recStack[node] = false
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,9 @@ func (d *TestCoverageDetector) Detect(ctx context.Context, path string, config *
|
||||
if _, err := os.Stat(coverFile); os.IsNotExist(err) {
|
||||
cmd := exec.CommandContext(ctx, "go", "test", "-coverprofile=coverage.out", "-covermode=atomic", "./...")
|
||||
cmd.Dir = path
|
||||
cmd.Run()
|
||||
if err := cmd.Run(); err != nil {
|
||||
return nil, fmt.Errorf("failed to run test coverage: %w", err)
|
||||
}
|
||||
|
||||
if _, err := os.Stat(coverFile); os.IsNotExist(err) {
|
||||
return nil, nil
|
||||
@@ -147,7 +149,9 @@ func (d *TestCoverageDetector) parseCoverageFile(path string) (map[string]Covera
|
||||
|
||||
countStr := parts[2]
|
||||
var count int
|
||||
fmt.Sscanf(countStr, "%d", &count)
|
||||
if _, err := fmt.Sscanf(countStr, "%d", &count); err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
start, end := d.parseRange(rangeStr)
|
||||
lines := end - start + 1
|
||||
@@ -169,8 +173,12 @@ func (d *TestCoverageDetector) parseRange(s string) (start, end int) {
|
||||
return 0, 0
|
||||
}
|
||||
|
||||
fmt.Sscanf(parts[0], "%d", &start)
|
||||
fmt.Sscanf(parts[1], "%d", &end)
|
||||
if _, err := fmt.Sscanf(parts[0], "%d", &start); err != nil {
|
||||
return 0, 0
|
||||
}
|
||||
if _, err := fmt.Sscanf(parts[1], "%d", &end); err != nil {
|
||||
return 0, 0
|
||||
}
|
||||
|
||||
return start, end
|
||||
}
|
||||
@@ -220,7 +228,9 @@ func (d *UntestedFuncDetector) Detect(ctx context.Context, path string, config *
|
||||
|
||||
countStr := parts[len(parts)-1]
|
||||
var count int
|
||||
fmt.Sscanf(countStr, "%d", &count)
|
||||
if _, err := fmt.Sscanf(countStr, "%d", &count); err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if count == 0 {
|
||||
fileRange := parts[0]
|
||||
@@ -283,8 +293,12 @@ func (d *UntestedFuncDetector) parseRange(s string) (start, end int) {
|
||||
if len(parts) != 2 {
|
||||
return 0, 0
|
||||
}
|
||||
fmt.Sscanf(parts[0], "%d", &start)
|
||||
fmt.Sscanf(parts[1], "%d", &end)
|
||||
if _, err := fmt.Sscanf(parts[0], "%d", &start); err != nil {
|
||||
return 0, 0
|
||||
}
|
||||
if _, err := fmt.Sscanf(parts[1], "%d", &end); err != nil {
|
||||
return 0, 0
|
||||
}
|
||||
return start, end
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user