13#include "clang/AST/Decl.h"
14#include "clang/AST/DeclBase.h"
15#include "clang/AST/DeclCXX.h"
16#include "clang/AST/RecursiveASTVisitor.h"
17#include "clang/Basic/SourceLocation.h"
18#include "clang/Tooling/Core/Replacement.h"
33class RemoveUsingNamespace :
public Tweak {
35 const char *id()
const override;
37 bool prepare(
const Selection &Inputs)
override;
38 Expected<Effect> apply(
const Selection &Inputs)
override;
39 std::string title()
const override {
40 return "Remove using namespace, re-qualify names instead";
42 llvm::StringLiteral kind()
const override {
47 const UsingDirectiveDecl *TargetDirective =
nullptr;
53 FindSameUsings(
const UsingDirectiveDecl &Target,
54 std::vector<const UsingDirectiveDecl *> &Results)
55 : TargetNS(Target.getNominatedNamespace()),
58 bool VisitUsingDirectiveDecl(UsingDirectiveDecl *D) {
59 if (D->getNominatedNamespace() != TargetNS ||
60 D->getDeclContext() != TargetCtx)
67 const NamespaceDecl *TargetNS;
68 const DeclContext *TargetCtx;
69 std::vector<const UsingDirectiveDecl *> &
Results;
73llvm::Expected<tooling::Replacement>
74removeUsingDirective(ASTContext &Ctx,
const UsingDirectiveDecl *D) {
75 auto &SM = Ctx.getSourceManager();
76 std::optional<Token> NextTok =
77 Lexer::findNextToken(D->getEndLoc(), SM, Ctx.getLangOpts());
78 if (!NextTok || NextTok->isNot(tok::semi))
79 return error(
"no semicolon after using-directive");
82 return tooling::Replacement(
84 CharSourceRange::getTokenRange(D->getBeginLoc(), NextTok->getLocation()),
85 "", Ctx.getLangOpts());
89bool isTopLevelDecl(
const SelectionTree::Node *Node) {
90 return Node->Parent &&
Node->Parent->ASTNode.get<TranslationUnitDecl>();
94bool isDeclaredIn(
const NamedDecl *LHS,
const DeclContext *RHS) {
95 const auto *D = LHS->getDeclContext();
96 while (D->isInlineNamespace() || D->isTransparentContext()) {
101 return D->Equals(RHS);
104bool RemoveUsingNamespace::prepare(
const Selection &Inputs) {
106 auto *CA = Inputs.ASTSelection.commonAncestor();
109 TargetDirective = CA->ASTNode.get<UsingDirectiveDecl>();
110 if (!TargetDirective)
112 if (!isa<Decl>(TargetDirective->getDeclContext()))
124 if (!TargetDirective->getNominatedNamespace()->using_directives().empty())
126 return isTopLevelDecl(CA);
129Expected<Tweak::Effect> RemoveUsingNamespace::apply(
const Selection &Inputs) {
130 auto &Ctx = Inputs.AST->getASTContext();
131 auto &SM = Ctx.getSourceManager();
134 std::vector<const UsingDirectiveDecl *> AllDirectives;
135 FindSameUsings(*TargetDirective, AllDirectives).TraverseAST(Ctx);
137 SourceLocation FirstUsingDirectiveLoc;
138 for (
auto *D : AllDirectives) {
139 if (FirstUsingDirectiveLoc.isInvalid() ||
140 SM.isBeforeInTranslationUnit(D->getBeginLoc(), FirstUsingDirectiveLoc))
141 FirstUsingDirectiveLoc = D->getBeginLoc();
146 std::vector<SourceLocation> IdentsToQualify;
147 for (
auto &D : Inputs.AST->getLocalTopLevelDecls()) {
150 [&](ReferenceLoc Ref) {
154 for (
auto *T : Ref.Targets) {
155 if (!isDeclaredIn(T, TargetDirective->getNominatedNamespace()))
157 auto Kind = T->getDeclName().getNameKind();
161 if (Kind == DeclarationName::CXXOperatorName)
173 if (Kind == DeclarationName::NameKind::CXXLiteralOperatorName)
176 SourceLocation
Loc = Ref.NameLoc;
177 if (
Loc.isMacroID()) {
184 if (!SM.isMacroArgExpansion(Loc))
186 Loc = SM.getFileLoc(Ref.NameLoc);
188 assert(
Loc.isFileID());
189 if (SM.getFileID(
Loc) != SM.getMainFileID())
191 if (SM.isBeforeInTranslationUnit(
Loc, FirstUsingDirectiveLoc))
193 IdentsToQualify.push_back(
Loc);
195 Inputs.AST->getHeuristicResolver());
198 llvm::sort(IdentsToQualify);
199 IdentsToQualify.erase(
200 std::unique(IdentsToQualify.begin(), IdentsToQualify.end()),
201 IdentsToQualify.end());
204 tooling::Replacements R;
205 for (
auto *D : AllDirectives) {
206 auto RemoveUsing = removeUsingDirective(Ctx, D);
208 return RemoveUsing.takeError();
209 if (
auto Err = R.add(*RemoveUsing))
210 return std::move(Err);
214 for (
auto Loc : IdentsToQualify) {
215 if (
auto Err = R.add(tooling::Replacement(Ctx.getSourceManager(),
Loc,
217 return std::move(Err);
219 return Effect::mainFileEdit(SM, std::move(R));
std::vector< CodeCompletionResult > Results
::clang::DynTypedNode Node
#define REGISTER_TWEAK(Subclass)
void findExplicitReferences(const Stmt *S, llvm::function_ref< void(ReferenceLoc)> Out, const HeuristicResolver *Resolver)
Recursively traverse S and report all references explicitly written in the code.
llvm::Error error(std::error_code EC, const char *Fmt, Ts &&... Vals)
std::string printUsingNamespaceName(const ASTContext &Ctx, const UsingDirectiveDecl &D)
Returns the name of the namespace inside the 'using namespace' directive, as written in the code.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
static const llvm::StringLiteral REFACTOR_KIND