Created
August 31, 2022 07:18
-
-
Save johannes-riecken/efcb356f42364281a8692c47b1d1a15b to your computer and use it in GitHub Desktop.
Add missing overrides using CodeQL
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"bufio" | |
_ "embed" | |
"encoding/json" | |
"io/ioutil" | |
"log" | |
"os" | |
"strings" | |
) | |
func main() { | |
err := mainAux() | |
if err != nil { | |
log.Fatal(err) | |
} | |
} | |
type region struct { | |
startLine int | |
startColumn int | |
endColumn int | |
} | |
func mainAux() error { | |
// missingOverridesJSON is generated from the output of the following commands: | |
// codeql database create testdb --language java | |
// codeql database analyze testdb ~/.codeql/packages/codeql/java-queries/0.3.2/Advisory/Declarations/MissingOverrideAnnotation.ql --format=sarif-latest --output=missing_overrides.json | |
missingOverridesJSON, err := ioutil.ReadFile("missing_overrides.json") | |
if err != nil { | |
return err | |
} | |
sarif, err := readSarif(missingOverridesJSON) | |
if err != nil { | |
return err | |
} | |
regions := getRegions(sarif) | |
// traverse regions backwards | |
for uri, fileRegions := range regions { | |
for i := range fileRegions { | |
r := fileRegions[i] | |
err := addOverrideAnnotation(uri, r) | |
if err != nil { | |
return err | |
} | |
} | |
} | |
return nil | |
} | |
// copy the file under fileName to a temporary file | |
// open the temporary file for reading and a new file under uri for writing | |
// loop over the file and write the lines to the new file | |
// if the line matches the region's startLine, then first write "@Override\n" | |
// then write the line | |
func addOverrideAnnotation(fileName string, r region) error { | |
// copy the file under fileName to fileName.tmp | |
// if <fileName>.tmp already exists, don't rename | |
tmpFileName := fileName + ".tmp" | |
if _, err := os.Stat(tmpFileName); os.IsNotExist(err) { | |
err := os.Rename(fileName, fileName+".tmp") | |
if err != nil { | |
return err | |
} | |
} | |
// open the temporary file for reading and a new file under uri for writing | |
f, err := os.Open(fileName + ".tmp") | |
if err != nil { | |
return err | |
} | |
defer func(f *os.File) { | |
_ = f.Close() | |
}(f) | |
w, err := os.Create(fileName) | |
if err != nil { | |
return err | |
} | |
defer func(w *os.File) { | |
_ = w.Close() | |
}(w) | |
// loop over the file and write the lines to the new file | |
// if the line number matches the region's startLine number, then first write "@override\n" | |
// then write the line | |
scanner := bufio.NewScanner(f) | |
for i := 0; scanner.Scan(); i++ { | |
lineText := scanner.Text() | |
if i == r.startLine-1 { | |
indentText := lineText[:len(lineText)-len(strings.TrimLeft(lineText, " "))] | |
s := indentText + "@Override\n" | |
// initialize indentText with the text of lineText's leading spaces | |
_, err := w.WriteString(s) | |
if err != nil { | |
return err | |
} | |
} | |
_, err := w.WriteString(lineText + "\n") | |
if err != nil { | |
return err | |
} | |
} | |
return nil | |
} | |
func getRegions(sarif map[string]interface{}) map[string][]region { | |
// read all the regions under the json path .runs[]|.results[]|.locations[]|.physicalLocation.region | |
regions := make(map[string][]region) | |
for _, run := range sarif["runs"].([]interface{}) { | |
for _, result := range run.(map[string]interface{})["results"].([]interface{}) { | |
for _, location := range result.(map[string]interface{})["locations"].([]interface{}) { | |
physicalLocation := location.(map[string]interface{})["physicalLocation"].(map[string]interface{}) | |
regionUntyped := physicalLocation["region"].(map[string]interface{}) | |
regionTyped := region{ | |
startLine: int(regionUntyped["startLine"].(float64)), | |
startColumn: int(regionUntyped["startColumn"].(float64)), | |
endColumn: int(regionUntyped["endColumn"].(float64)), | |
} | |
uri := physicalLocation["artifactLocation"].(map[string]interface{})["uri"].(string) | |
if regions[uri] == nil { | |
regions[uri] = make([]region, 0) | |
} | |
regions[uri] = append(regions[uri], regionTyped) | |
} | |
} | |
} | |
return regions | |
} | |
// readSarif unmarshals missing_overrides.json into a map[string]interface{} | |
func readSarif(contents []byte) (map[string]interface{}, error) { | |
var sarif map[string]interface{} | |
err := json.Unmarshal(contents, &sarif) | |
if err != nil { | |
return nil, err | |
} | |
return sarif, nil | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment