This is an archive of the discontinued LLVM Phabricator instance.

[AST] Treat semantic form of InitListExpr as implicit code in traversals
ClosedPublic

Authored by ilya-biryukov on Jul 15 2019, 10:55 AM.

Details

Summary

In particular, do not traverse the semantic form if shouldVisitImplicitCode()
returns false.

This simplifies the common case of traversals, avoiding the need to
worry about some expressions being traversed twice.

No tests break after the change, the change would allow to simplify at
least one of the usages, i.e. r366070 which had to handle this in
clangd.

Diff Detail

Repository
rL LLVM

Event Timeline

ilya-biryukov created this revision.Jul 15 2019, 10:55 AM
Herald added a project: Restricted Project. · View Herald TranscriptJul 15 2019, 10:55 AM
Herald added a subscriber: kadircet. · View Herald Transcript
ilya-biryukov edited the summary of this revision. (Show Details)Jul 15 2019, 11:00 AM

Please add tests to llvm/tools/clang/unittests/Tooling/RecursiveASTVisitorTests/.

clang/include/clang/AST/RecursiveASTVisitor.h
2332 ↗(On Diff #209913)

Instead of adding a whole new if statement, could you wrap the second existing TRY_TO in if(shouldVisitImplicitCode()) ?

ilya-biryukov added inline comments.Jul 16 2019, 12:05 AM
clang/include/clang/AST/RecursiveASTVisitor.h
2332 ↗(On Diff #209913)

Despite looking very similar, that would not be equivalent to the current version.

For most init lists (that do not have alternative "form"), the following invariants hold:

InitList* E = ...;
assert(E->isSemanticForm());
assert(E->isSyntacticForm()); 
assert(E->getSynacticForm() == nullptr);

This subtle fact means the current code does not traversed the list twice if they do not have an alternative form (either semantic or syntactic).

Now, if we only run the first statement, we will call TraverseSynOrSemInitListExpr(S->getSyntacticForm()) and S->getSyntacticForm() returns null. So we don't traverse anything.

I tried various ways to keep both calls, but they all ended up being too complicated, hence the final version. Let me know if you see a better way to address this.

  • Add a test.
ilya-biryukov marked an inline comment as done.Jul 16 2019, 3:22 AM
ilya-biryukov added inline comments.
clang/include/clang/AST/RecursiveASTVisitor.h
2332 ↗(On Diff #209913)

To make the last sentence less confusing:
I tried various ways to keep only two calls, but they were too complicated and I ended up introducing an extra call to TraverseSyn... instead.

ilya-biryukov marked an inline comment as not done.Jul 16 2019, 3:24 AM
gribozavr accepted this revision.Jul 19 2019, 10:42 AM
gribozavr added inline comments.
clang/include/clang/AST/RecursiveASTVisitor.h
2332 ↗(On Diff #209913)

assert(E->getSynacticForm() == nullptr);

That's... a really nice API.

What do you think about the following:

if (S->isSyntacticForm() && S->isSemanticForm()) {
  // `S` does not have alternative forms, traverse the only form that's available.
  TRY_TO(TraverseSynOrSemInitListExpr(S, Queue));
  return true;
}

TRY_TO(TraverseSynOrSemInitListExpr(
  S->isSemanticForm() ? S->getSyntacticForm() : S, Queue));
if (getDerived().shouldVisitImplicitCode()) {
  TRY_TO(TraverseSynOrSemInitListExpr(
    S->isSyntacticForm() ? S->getSemanticForm() : S, Queue));
}
This revision is now accepted and ready to land.Jul 19 2019, 10:42 AM
ilya-biryukov marked an inline comment as done.
  • Rewrite code as suggested in the review
clang/include/clang/AST/RecursiveASTVisitor.h
2332 ↗(On Diff #209913)

Definitely reads better, updated the revision accordingly.

This revision was automatically updated to reflect the committed changes.
Herald added a project: Restricted Project. · View Herald TranscriptJul 22 2019, 3:02 AM