This is an archive of the discontinued LLVM Phabricator instance.

[clangd] Improve action `RemoveUsingNamespace` for user-defined literals
AbandonedPublic

Authored by v1nh1shungry on Nov 11 2022, 1:04 AM.

Details

Summary

This patch aims at:

When triggering the action RemoveUsingNamespace for

namespace ns {
long double operator""_a(long double);
}
using namespace n^s;
int main() {
  1.5_a;
}

, the codes change to

// namespace ns above
int main() {
  using ns::operator""_a;
  1.5_a;
}

Inspired by the discussion in https://reviews.llvm.org/D137550 and below.

Diff Detail

Event Timeline

v1nh1shungry created this revision.Nov 11 2022, 1:04 AM
Herald added a project: Restricted Project. · View Herald TranscriptNov 11 2022, 1:04 AM
v1nh1shungry requested review of this revision.Nov 11 2022, 1:04 AM

This looks really cool :)

clang-tools-extra/clangd/refactor/tweaks/RemoveUsingNamespace.cpp
133

nit: const auto

249

If you're sorting and removing duplicates in the end anyway, maybe llvm::StringSet would be a better fit instead of vector<string>?

clang-tools-extra/clangd/unittests/tweaks/RemoveUsingNamespaceTests.cpp
286

Your code also handles cases where there are multiple inline namespaces involved, right? If so, it would be a good idea also test this here (i.e. add ns3 with another user-defined literal)

Apply the review suggestions

@tom-anders Thank you for reviewing and giving suggestions!

Hope I use the llvm::StringSet correctly.

nridge added a subscriber: nridge.Nov 13 2022, 12:09 AM

LGTM, but I'll give @kadircet a chance to review as well

thanks for pinging @tom-anders , i've added some concerns about the behaviour in general. sorry if these are discussed somewhere else but i've missed.

clang-tools-extra/clangd/unittests/tweaks/RemoveUsingNamespaceTests.cpp
314

sorry i am having trouble understanding why we are:

  • only handling user defined literals from inline namespaces and not others?
  • producing using directives and not using declarations
  • inserting these at top level rather than where the usage is

@kadircet Thank you for reviewing and giving suggestions! Please check my reply to your concerns. Sorry if I misunderstood anything.

clang-tools-extra/clangd/unittests/tweaks/RemoveUsingNamespaceTests.cpp
314

The first question:

Because others have already been handled. Say

namespace a { inline namespace b { void foobar(); } }
using namespace ^a;
int main() { foobar(); }

can become

namespace a { inline namespace b { void foobar(); } }

int main() { a::foobar(); }

But user-defined literals just can't add a qualifier, right?


The second question:

Yes, this is a good idea. I didn't realize we can use using-declarations instead of using-directives.


The last question:

Hmm, I think it is cleaner if there are multiple usages. Since we can only remove the using-directives at the top level, this doesn't hurt anything. And it is the easiest solution to implement as well :)

kadircet added inline comments.Nov 16 2022, 5:17 AM
clang-tools-extra/clangd/unittests/tweaks/RemoveUsingNamespaceTests.cpp
314

Because others have already been handled. Say

i was emphasizing on the difference between user defined literals inside inline namespaces, and user defined literals from regular namespaces. not other types of decls inside an inline namespace, eg:

namespace ns { long double operator"" _o(long double); }

we should also introduce a using-decl for _o despite it not being inside an inline namespace.

314

Hmm, I think it is cleaner if there are multiple usages. Since we can only remove the using-directives at the top level, this doesn't hurt anything. And it is the easiest solution to implement as well :)

right, but introducing these at the top level will have unintended consequences (e.g. if this is a header, symbols will all of a sudden be visible in all the dependents).

@kadircet Thank you for the excellent suggestions! Will dive into it to figure out the implementations.

clang-tools-extra/clangd/unittests/tweaks/RemoveUsingNamespaceTests.cpp
314

You're right. Sorry for misunderstanding it.

314

Yes, I agree.

apply review's suggestions

Reimplemented.

Note:

Failed to find a way to use ReferenceLoc to insert the using-declarations.
Currently I have to visit the Decl again and look for CompoundStmt, if there
is any target user-defined literal in the CompoundStmt I mark it so that
I can add the using-declaration in it later.

In this way this implementation covers many cases, and does nothing for user-defined
literals used in the top-level. But it can cause redundancy and is too complex.

Note:
Currently if there are user-defined literals, this patch will find them and get their
CompoundStmt parents. If there is one, it will record the parent so that it can add the
using-declaration in it later. If there is not, it means the user-defined literal is in
the top-level, and it is reasonable to do nothing for it. I choose CompoundStmt because
it covers many cases, like blocks, functions, lambdas.

Since I failed to find a way to use only ReferenceLoc to get the parents, I have to
traverse the whole Decl again to find out the DeclRefExpr and then use ASTContext
to get its parents. Also this implementation can cause redundance in some cases.

I think this patch is ready for another review now.

This comment was removed by v1nh1shungry.

Insert the using-declarations in the outermost CompoundStmt instead of
the innermost one. Can reduce some potential rebundancy.

v1nh1shungry edited the summary of this revision. (Show Details)Dec 20 2022, 12:52 AM
v1nh1shungry abandoned this revision.Dec 21 2022, 9:06 AM

Abandon because of the terrible implementation.

  • The cost seems to be higher than the value.
  • The place to insert isn't good enough.