Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -152,22 +152,33 @@ if (!node.canAccess() || node.hasChanges()) {
}

exec(query, node)

// Both ways out of this loop have to clean up the same way. The condition is re-checked at the
// top as well as after the action, because the query, cursor and node are shared and can be
// closed or edited by another thread at any point; whichever check trips, the caller's
// onClosedOrEdited must run so it can discard whatever it had half-built, and the match it was
// holding has to go back to the pool (ADFA-5414).
var match = nextMatch()
while (matchCondition(match) && whileTrue(match)) {
while (match != null) {
if (!matchCondition(match)) {
logCannotProceed(query, node, debugName, debugLogging)
onClosedOrEdited()
(match as? TreeSitterQueryMatch?)?.recycle()
break
}

if (!whileTrue(match)) {
// The caller asked to stop; nothing is wrong, so no onClosedOrEdited.
(match as? TreeSitterQueryMatch?)?.recycle()
break
}

val result = action(match)

if (!matchCondition(match)) {
if (debugLogging) {
log.debug(
"$debugName: Cannot proceed with query operation.",
"cursor.canAccess=${canAccess()}",
"query.canAccess=${query.canAccess()}",
"node.canAccess=${node.canAccess()}",
"node.hasChanges=${node.canAccess() && node.hasErrors()}"
)
}
logCannotProceed(query, node, debugName, debugLogging)
onClosedOrEdited()
(match as? TreeSitterQueryMatch?)?.recycle()
break
}

Expand All @@ -188,3 +199,26 @@ if (recycleNodeAfterUse && node is TreeSitterNode && !node.isRecycled) {

return null
}

/**
* Diagnostic for the two places [doSafeExecQueryCursor] gives up on a traversal.
*/
@PublishedApi
internal fun TSQueryCursor.logCannotProceed(
query: TSQuery,
node: TSNode,
debugName: String,
debugLogging: Boolean,
) {
if (!debugLogging) {
return
}

log.debug(
"$debugName: Cannot proceed with query operation.",
"cursor.canAccess=${canAccess()}",
"query.canAccess=${query.canAccess()}",
"node.canAccess=${node.canAccess()}",
"node.hasChanges=${node.canAccess() && node.hasChanges()}",
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -328,8 +328,11 @@ class TsAnalyzeWorker(
}

private fun updateCodeBlocks() {
if (languageSpec.blocksQuery.patternCount == 0 ||
!languageSpec.blocksQuery.canAccess() ||
// canAccess() first: getPatternCount() calls checkAccess() internally, so on a closed query
// reading patternCount throws before the guard beside it can return (ADFA-5416). The sibling
// site in TsBracketPairs already has the operands this way round.
if (!languageSpec.blocksQuery.canAccess() ||
languageSpec.blocksQuery.patternCount == 0 ||
tree?.canAccess() != true
) {
return
Expand Down
Loading