feat: cppcheck parser (#28)
	
		
			
	
		
	
	
		
	
		
			All checks were successful
		
		
	
	
		
			
				
	
				continuous-integration/drone/push Build is passing
				
			
		
		
	
	
				
					
				
			
		
			All checks were successful
		
		
	
	continuous-integration/drone/push Build is passing
				
			Co-authored-by: zjc_he <zjc_he@sjtu.edu.cn> Reviewed-on: FOCS-dev/JOJ3#28 Reviewed-by: 张泊明518370910136 <bomingzh@sjtu.edu.cn> Co-authored-by: 张佳澈520370910044 <zjc_he@sjtu.edu.cn> Co-committed-by: 张佳澈520370910044 <zjc_he@sjtu.edu.cn>
This commit is contained in:
		
							parent
							
								
									29627d2760
								
							
						
					
					
						commit
						5ac760814d
					
				
							
								
								
									
										4
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							|  | @ -30,3 +30,7 @@ | |||
| 	path = examples/keyword/clangtidy/sillycode | ||||
| 	url = ssh://git@focs.ji.sjtu.edu.cn:2222/FOCS-dev/JOJ3-examples.git | ||||
| 	branch = keyword/clangtidy/sillycode | ||||
| [submodule "examples/cppcheck/sillycode"] | ||||
| 	path = examples/cppcheck/sillycode | ||||
| 	url = ssh://git@focs.ji.sjtu.edu.cn:2222/FOCS-dev/JOJ3-examples.git | ||||
| 	branch = cppcheck/sillycode | ||||
|  |  | |||
							
								
								
									
										1
									
								
								examples/cppcheck/sillycode
									
									
									
									
									
										Submodule
									
								
							
							
								
								
								
								
								
								
							
						
						
									
										1
									
								
								examples/cppcheck/sillycode
									
									
									
									
									
										Submodule
									
								
							|  | @ -0,0 +1 @@ | |||
| Subproject commit 0815ab90d72641fc274231c075282567e9e17865 | ||||
|  | @ -2,6 +2,7 @@ package parsers | |||
| 
 | ||||
| import ( | ||||
| 	_ "focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3/internal/parsers/clangtidy" | ||||
| 	_ "focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3/internal/parsers/cppcheck" | ||||
| 	_ "focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3/internal/parsers/cpplint" | ||||
| 	_ "focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3/internal/parsers/diff" | ||||
| 	_ "focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3/internal/parsers/dummy" | ||||
|  |  | |||
							
								
								
									
										9
									
								
								internal/parsers/cppcheck/meta.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								internal/parsers/cppcheck/meta.go
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,9 @@ | |||
| package cppcheck | ||||
| 
 | ||||
| import "focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3/internal/stage" | ||||
| 
 | ||||
| var name = "cppcheck" | ||||
| 
 | ||||
| func init() { | ||||
| 	stage.RegisterParser(name, &CppCheck{}) | ||||
| } | ||||
							
								
								
									
										85
									
								
								internal/parsers/cppcheck/parser.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								internal/parsers/cppcheck/parser.go
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,85 @@ | |||
| package cppcheck | ||||
| 
 | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3/internal/stage" | ||||
| 	"github.com/criyle/go-judge/envexec" | ||||
| ) | ||||
| 
 | ||||
| type CppCheck struct{} | ||||
| 
 | ||||
| type Match struct { | ||||
| 	Severity []string | ||||
| 	Score    int | ||||
| } | ||||
| 
 | ||||
| type Conf struct { | ||||
| 	Score   int `default:"100"` | ||||
| 	Matches []Match | ||||
| } | ||||
| 
 | ||||
| type Record struct { | ||||
| 	File     string `json:"file"` | ||||
| 	Line     int    `json:"line"` | ||||
| 	Column   int    `json:"column"` | ||||
| 	Severity string `json:"severity"` | ||||
| 	Message  string `json:"message"` | ||||
| 	Id       string `json:"id"` | ||||
| } | ||||
| 
 | ||||
| func Parse(executorResult stage.ExecutorResult, conf Conf) stage.ParserResult { | ||||
| 	// stdout := executorResult.Files["stdout"]
 | ||||
| 	stderr := executorResult.Files["stderr"] | ||||
| 
 | ||||
| 	if executorResult.Status != stage.Status(envexec.StatusAccepted) { | ||||
| 		return stage.ParserResult{ | ||||
| 			Score: 0, | ||||
| 			Comment: fmt.Sprintf( | ||||
| 				"Unexpected executor status: %s.\nStderr: %s", | ||||
| 				executorResult.Status, stderr, | ||||
| 			), | ||||
| 		} | ||||
| 	} | ||||
| 	records := make([]Record, 0) | ||||
| 	lines := strings.Split(stderr, "\n") | ||||
| 	for _, line := range lines { | ||||
| 		if strings.TrimSpace(line) == "" { | ||||
| 			continue | ||||
| 		} | ||||
| 		var record Record | ||||
| 		_ = json.Unmarshal([]byte(line), &record) | ||||
| 		records = append(records, record) | ||||
| 	} | ||||
| 	comment, score, err := GetResult(records, conf) | ||||
| 	if err != nil { | ||||
| 		return stage.ParserResult{ | ||||
| 			Score: 0, | ||||
| 			Comment: fmt.Sprintf( | ||||
| 				"Unexpected parser error: %s.", | ||||
| 				err, | ||||
| 			), | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return stage.ParserResult{ | ||||
| 		Score:   score, | ||||
| 		Comment: comment, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (*CppCheck) Run(results []stage.ExecutorResult, confAny any) ( | ||||
| 	[]stage.ParserResult, bool, error, | ||||
| ) { | ||||
| 	conf, err := stage.DecodeConf[Conf](confAny) | ||||
| 	if err != nil { | ||||
| 		return nil, true, err | ||||
| 	} | ||||
| 	var res []stage.ParserResult | ||||
| 	for _, result := range results { | ||||
| 		res = append(res, Parse(result, *conf)) | ||||
| 	} | ||||
| 	return res, false, nil | ||||
| } | ||||
							
								
								
									
										66
									
								
								internal/parsers/cppcheck/score.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								internal/parsers/cppcheck/score.go
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,66 @@ | |||
| package cppcheck | ||||
| 
 | ||||
| import "fmt" | ||||
| 
 | ||||
| type Severity int | ||||
| 
 | ||||
| const ( | ||||
| 	ERROR Severity = iota | ||||
| 	WARNING | ||||
| 	PROBABILITY | ||||
| 	PERFORMANCE | ||||
| 	STYLE | ||||
| 	INFORMATION | ||||
| 	UNKNOWN | ||||
| ) | ||||
| 
 | ||||
| func severityFromString(severityString string) (Severity, error) { | ||||
| 	switch severityString { | ||||
| 	case "error": | ||||
| 		return ERROR, nil | ||||
| 	case "warning": | ||||
| 		return WARNING, nil | ||||
| 	case "probability": | ||||
| 		return PROBABILITY, nil | ||||
| 	case "performance": | ||||
| 		return PERFORMANCE, nil | ||||
| 	case "style": | ||||
| 		return STYLE, nil | ||||
| 	case "information": | ||||
| 		return INFORMATION, nil | ||||
| 	default: | ||||
| 		return UNKNOWN, fmt.Errorf("unkown severity type \"%s\" for cppcheck", severityString) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func GetResult(records []Record, conf Conf) (string, int, error) { | ||||
| 	result := "### Test results summary\n\n" | ||||
| 	var severityCounts [6]int | ||||
| 	var severityScore [6]int | ||||
| 	score := conf.Score | ||||
| 
 | ||||
| 	for _, match := range conf.Matches { | ||||
| 		severities := match.Severity | ||||
| 		score := match.Score | ||||
| 		for _, severityString := range severities { | ||||
| 			severity, err := severityFromString(severityString) | ||||
| 			if err != nil { | ||||
| 				return "", 0, err | ||||
| 			} | ||||
| 			severityScore[int(severity)] = score | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	for _, record := range records { | ||||
| 		severity, _ := severityFromString(record.Severity) | ||||
| 		severityCounts[int(severity)] += 1 | ||||
| 		score -= severityScore[int(severity)] | ||||
| 	} | ||||
| 	result += fmt.Sprintf("1. error: %d\n", severityCounts[0]) | ||||
| 	result += fmt.Sprintf("2. warning: %d\n", severityCounts[1]) | ||||
| 	result += fmt.Sprintf("3. probability: %d\n", severityCounts[2]) | ||||
| 	result += fmt.Sprintf("4. performance: %d\n", severityCounts[3]) | ||||
| 	result += fmt.Sprintf("5. style: %d\n", severityCounts[4]) | ||||
| 	result += fmt.Sprintf("6. information: %d", severityCounts[5]) | ||||
| 	return result, score, nil | ||||
| } | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user