Add ability to use contextual queries to find references when already on a reference
I'm not exactly sure whether this is a feature request or a bug report. Regardless, this is behaviour that is not implemented, but I would expect it to be.
When running the find references contextual query, on a token in a database source file, no references will be found if the token represents a reference itself. References will only be found if the selected token is a declaration. For instance:
int /* 1 */ myMethod() {
/* 2 */ myMethod();
/* 3 */ myMethod();
}
If you place the caret at 2 or 3, no references will be found. If you place the caret at 1 References will be found at 2 and 3. Most other language servers will find references for 2 and 3 regardless of which reference is selected.
The problem is not related to the queries themselves. Rather, it happens here: https://github.com/aeisenberg/vscode-codeql/blob/353a87de12ca818293aeb3199d057a23a24cc403/extensions/ql-vscode/src/contextual/templateProvider.ts#L70-L70
This function will take all possible results and filter out results that do not contain the selected position. This makes sense when the selected position is the declaration, but it does not make sense if the position is a reference.
I don't think that diagnosis isn't quite right, the problem is deeper. Currently the "find references" is only the inverse of jump-to-def so the query doesn't handle that case. I think was wrong in my initial implementation.
There are 2 solutions I can see
- Make the query an actual find references query.
- Run jump-to-def before find references and use that position.
Option 1 allows us to potentially give more correct results as in some cases the defintion may be missing (e.g. in java a method in a ".class" file won't have a definition but we can find all references to it. It does end up with a different problem. We end up with quadratic blowup in some cases. It worse for C/C++ files. This is because we run find-references at the file level so if a common thing (e.g. true, uint32_t) is just a preprocessor definition we would find all references to it for each time it is mentioned in a file. This is a bit bad currently when finding references in those headers but blows up easily in files that mention them multiple times (e.g. a giant boolean array). The solution for that is to probably avoid querying for all results and make the contextual query work on a single position. I don't think we really need the file level cacching for find references as users probably don't trigger it many times in the same file (jump-to-def is special in that case because vscode will trigger it to see where to put the underlines). There is also a slightly slower expectation on find references (i.e. 2-3 seconds is probably fine). That does then meaning changing the shape of the query though which is a bit awkward.
The second option is probably easy to implement now in vscode as it simply involves combining the two queries. it may be a bit awkaward in some cases where the positions are slightly off or when there are multiple overlapping defintions (c++ templates).
I was considering option 2. Mostly because it is simple enough that it doesn't require changing any queries themselves. However, there is ambiguity in Java and C++ (and potentially JavaScript and all the other languages due to inheritance, interfaces, etc). So, if we run find defs and get multiple definitions, do we run find refs on all of them? Possibly.
it may be a bit awkaward in some cases where the positions are slightly off
How big of a problem is this? I haven't seen it in practice.