ilya-biryukov created this revision.
ilya-biryukov added a reviewer: sammccall.
Herald added subscribers: kadircet, arphaman, jkorous, MaskRay, ioeric, mgorny.
Repository:
rCTE Clang Tools Extra
https://reviews.llvm.org/D56610
Files:
clangd/CMakeLists.txt
clangd/refactor/actions/QualifyName.cpp
clangd/refactor/actions/QualifyName.h
Index: clangd/refactor/actions/QualifyName.h
===================================================================
--- /dev/null
+++ clangd/refactor/actions/QualifyName.h
@@ -0,0 +1,32 @@
+//===--- QualifyNameAction.h -------------------------------------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// A code action that fully qualifies a name under cursor.
+// Before:
+// using namespace std;
+// ^vector<int> foo;
+// After:
+// std::vector<int> foo;
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_REFACTOR_ACTIONS_QUALIFYNAME_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_REFACTOR_ACTIONS_QUALIFYNAME_H
+
+#include "refactor/ActionProvider.h"
+
+namespace clang {
+namespace clangd {
+
+class QualifyName : public ActionProvider {
+ llvm::Optional<PreparedAction> prepare(const ActionInputs &Inputs) override;
+};
+
+} // namespace clangd
+} // namespace clang
+
+#endif
\ No newline at end of file
Index: clangd/refactor/actions/QualifyName.cpp
===================================================================
--- /dev/null
+++ clangd/refactor/actions/QualifyName.cpp
@@ -0,0 +1,150 @@
+//===--- QualifyNameAction.cpp -----------------------------------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "QualifyName.h"
+#include "AST.h"
+#include "ClangdUnit.h"
+#include "SourceCode.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/AST/TypeLoc.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Tooling/Tooling.h"
+
+namespace clang {
+namespace clangd {
+
+namespace {
+struct Reference {
+ SourceLocation Begin;
+ NamedDecl *Target = nullptr;
+
+ operator bool() const { return Target != nullptr; }
+};
+
+NamedDecl *toReferencedDecl(NestedNameSpecifier *NNS) {
+ switch (NNS->getKind()) {
+ case clang::NestedNameSpecifier::Namespace:
+ return NNS->getAsNamespace();
+ case clang::NestedNameSpecifier::NamespaceAlias:
+ return NNS->getAsNamespaceAlias();
+ case clang::NestedNameSpecifier::TypeSpec:
+ case clang::NestedNameSpecifier::TypeSpecWithTemplate:
+ return nullptr; // FIXME: handle this situation, retrieve the thing
+ // referenced inside a type.
+ case clang::NestedNameSpecifier::Identifier:
+ case clang::NestedNameSpecifier::Super:
+ case clang::NestedNameSpecifier::Global: // FIXME: could return
+ // TranslationUnitDecl.
+ return nullptr;
+ return nullptr;
+ }
+ llvm_unreachable("unhandled NestedNameSpecifier kind.");
+}
+
+class LocateInsertLoc : public RecursiveASTVisitor<LocateInsertLoc> {
+public:
+ LocateInsertLoc(ASTContext &Ctx, SourceLocation CursorLoc,
+ Reference &UnqualRef)
+ : Ctx(Ctx), CursorLoc(CursorLoc), UnqualRef(UnqualRef) {}
+
+ bool shouldWalkTypesOfTypeLocs() const { return false; }
+
+ // FIXME: RAT does not have VisitNestedNameSpecifierLoc. Should we add that?
+ bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {
+ if (!RecursiveASTVisitor::TraverseNestedNameSpecifierLoc(NNS))
+ return false;
+ return VisitNestedNameSpecifierLoc(NNS);
+ }
+
+ bool VisitNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {
+ if (NNS.getPrefix())
+ return true; // we want only unqualified names.
+ auto &SM = Ctx.getSourceManager();
+ auto Rng = toHalfOpenFileRange(SM, Ctx.getLangOpts(), NNS.getSourceRange());
+ if (!Rng)
+ return true;
+ if (!halfOpenRangeContains(SM, *Rng, CursorLoc))
+ return true;
+ auto *Target = toReferencedDecl(NNS.getNestedNameSpecifier());
+ if (!Target)
+ return true; // continue traversal to recurse into types, if any.
+ UnqualRef.Begin = Rng->getBegin();
+ UnqualRef.Target = Target;
+ return false; // we found the insertion point.
+ }
+
+ bool VisitDeclRefExpr(DeclRefExpr *E) {
+ if (E->hasQualifier())
+ return true; // we want only unqualified names.
+ auto &SM = Ctx.getSourceManager();
+ auto Rng = toHalfOpenFileRange(SM, Ctx.getLangOpts(), E->getSourceRange());
+ if (!Rng)
+ return true;
+ if (!halfOpenRangeContains(SM, *Rng, CursorLoc))
+ return true;
+ UnqualRef.Begin = Rng->getBegin();
+ UnqualRef.Target = E->getFoundDecl();
+ return false;
+ }
+
+ bool VisitTagTypeLoc(TagTypeLoc Loc) {
+ auto &SM = Ctx.getSourceManager();
+ auto Rng = toHalfOpenFileRange(SM, Ctx.getLangOpts(), Loc.getSourceRange());
+ if (!Rng)
+ return true;
+ if (!halfOpenRangeContains(SM, *Rng, CursorLoc))
+ return true;
+ UnqualRef.Begin = Rng->getBegin();
+ UnqualRef.Target = Loc.getDecl();
+ return false;
+ }
+
+ bool VisitTypedefTypeLoc(TypedefTypeLoc Loc) {
+ auto &SM = Ctx.getSourceManager();
+ auto Rng = toHalfOpenFileRange(SM, Ctx.getLangOpts(), Loc.getSourceRange());
+ if (!Rng)
+ return true;
+ if (!halfOpenRangeContains(SM, *Rng, CursorLoc))
+ return true;
+ UnqualRef.Begin = Rng->getBegin();
+ UnqualRef.Target = Loc.getTypedefNameDecl();
+ return false;
+ }
+
+private:
+ ASTContext &Ctx;
+ SourceLocation CursorLoc;
+ Reference &UnqualRef;
+};
+} // namespace
+
+llvm::Optional<PreparedAction>
+QualifyName::prepare(const ActionInputs &Inputs) {
+ auto &Ctx = Inputs.AST.getASTContext();
+ Reference Ref;
+ LocateInsertLoc(Ctx, Inputs.Cursor, Ref).TraverseAST(Ctx);
+ if (!Ref)
+ return llvm::None;
+ auto *Parent = Ref.Target->getDeclContext();
+ if (!Parent->isNamespace())
+ return llvm::None; // avoid complicated cases, qualify only with namespaces.
+ std::string Qualifier = printNamespaceScope(*Parent);
+ if (Qualifier.empty())
+ return llvm::None; // happens for decls from global namespaces.
+ tooling::Replacements R;
+ if (auto Err = R.add(tooling::Replacement(Ctx.getSourceManager(), Ref.Begin,
+ 0, Qualifier))) {
+ llvm::consumeError(std::move(Err));
+ return llvm::None;
+ }
+ return PreparedAction(llvm::formatv("Add '{0}' qualifier", Qualifier),
+ std::move(R));
+}
+
+} // namespace clangd
+} // namespace clang
Index: clangd/CMakeLists.txt
===================================================================
--- clangd/CMakeLists.txt
+++ clangd/CMakeLists.txt
@@ -64,6 +64,7 @@
index/dex/Trigram.cpp
refactor/ActionProvider.cpp
+ refactor/actions/QualifyName.cpp
LINK_LIBS
clangAST
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits