codeql
codeql copied to clipboard
Writing a query to find declarations of nested structs in Golang.
Description of the issue
I want to write a query to find the nested structs in an struct in Golang. Let's say my struct is something like:
type SomeStruct struct {
field1 int
field2 dto.NewStruct
field3 []*statusCode
field4 map[string]http.Response
field5 map[category.Category]map[time.Time]*http.Header
field6 []statusCode
field7 []*time.Time
field8 http.Request
field9 statusCode
}
and I want to write a query that gives me all the nested types in this struct ie. statusCode,Response,Category,Time,Header,NewStruct etc.
The field types can be more complex than what is mentioned here.
My main problem statement is to find the declarations of these nested structs, which I will continue my query by finding all typedecl with their idents matching with the above mentioned idents while matching the import path and the filepath for nested objects from different packages like dto.NewStruct. If there is some better approach please suggest.
Please suggest me an approach.
Hi @aaaayush-n,
It sounds like you're doing the right thing, but it's a bit hard to make suggestions with seeing the query code you currently have. Would you be able to share the current version of your query?
@jketema
/**
* @id go/get-location
* @kind problem
* @problem.severity recommendation
*/
import go
class MyFunc extends Decl{
TypeDecl typeDecl;
Ident ident;
TypeDecl getObject(string objectName,string objDirPath){
ident.getAPrimaryQlClass()="TypeName"
and ident.toString()=objectName
and ident.getParent().getParent()=typeDecl
and typeDecl.getFile().toString().replaceAll(typeDecl.getFile().getBaseName().toString(), "").substring(0, typeDecl.getFile().toString().replaceAll(typeDecl.getFile().getBaseName().toString(), "").length()-1)=objDirPath
and
result=typeDecl
}
}
from string objectName
, MyFunc func
,TypeDecl object
,string objDirPath
,FieldDecl fieldDecl
where objectName="MyStruct"
and objDirPath="path/to/src/directory"
and object=func.getObject(objectName,objDirPath)
select object,"MyObject"
Now I want to find the nested objects inside TypeDecl object
I was thinking of adding
ident.getAPrimaryQLClass()="TypeName"
and ident.getEnclosingTypeDecl()=object
select ident,"MyNestedObjects"
but there is no such getEnclosingTypeDecl() predicate, I can't do ident.getParent()=object because idk how deep in AST my ident will be.
Suggest me some way to find out how to figure this out.
Hi @aaaayush-n 👋
Thanks for sharing your query! What you have written looks a bit unusual and I am guessing you are coming from a background of object-oriented and imperative programming languages. If you haven't seen our documentation for the QL language yet, I'd recommend having a look for lots of advice for how to write good QL. In particular, you may find the section on recursion relevant to your question.
The getAPrimaryQLClass predicate is mainly intended for debugging, not for actual queries. For example, you don't need the MyFunc class and your getObject predicate could be simplified to:
TypeDecl getObject(string objectName,string objDirPath){
exists(TypeName tn |
tn.toString()=objectName and
tn.getParent().getParent()=result and
result.getFile().toString().replaceAll(result.getFile().getBaseName().toString(), "").substring(0, result.getFile().toString().replaceAll(result.getFile().getBaseName().toString(), "").length()-1)=objDirPath
)
}
Use concrete types rather than strings whenever possible. This can probably be further simplified as well, particularly the last line.
In any case, the way I would break this problem down is to start with a predicate which, given some TypeDecl, finds all the TypeNames you are interested in. Something like:
predicate isUsedInTypeDecl(TypeDecl decl, TypeName ty) {
result = ty.getParent()
}
You can then extend/modify this to find all TypeNames with a corresponding TypeDecl of their own. From there, you can apply the predicate recursively.
@mbg
predicate isUsedInTypeDecl(TypeDecl decl, TypeName ty) { result = ty.getParent() }
This would only give me the statusCode in field9 in context of example struct I gave above (that too on having ty.getParent().getParent().getParent() as the AST structure is TypeName>FieldDecl>StructTypeExpr>TypeDecl)
I fail to see, how I would call this recursively to get the other types.
Please help me with this.
The definition I gave for isUsedInTypeDecl is just an example. You can tweak it to suit your needs. You can use the resulting TypeNames for the initial TypeDecl to find TypeNames that have corresponding TypeDecls, which you can then recurse on.