#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/Basic/SourceLocation.h"
-#include "clang/Tooling/Refactoring/Rename/USRFindingAction.h"
#include "clang/Tooling/Syntax/Tokens.h"
#include "llvm/ADT/None.h"
#include "llvm/ADT/STLExtras.h"
return OtherFile;
}
+// Canonical declarations help simplify the process of renaming. Examples:
+// - Template's canonical decl is the templated declaration (i.e.
+// ClassTemplateDecl is canonicalized to its child CXXRecordDecl,
+// FunctionTemplateDecl - to child FunctionDecl)
+// - Given a constructor/destructor, canonical declaration is the parent
+// CXXRecordDecl because we want to rename both type name and its ctor/dtor.
+// - All specializations are canonicalized to the primary template. For example:
+//
+// template <typename T, int U>
+// bool Foo = true; (1)
+//
+// template <typename T>
+// bool Foo<T, 0> = true; (2)
+//
+// template <>
+// bool Foo<int, 0> = true; (3)
+//
+// Here, both partial (2) and full (3) specializations are canonicalized to (1)
+// which ensures all three of them are renamed.
+const NamedDecl *canonicalRenameDecl(const NamedDecl *D) {
+ if (const auto *VarTemplate = dyn_cast<VarTemplateSpecializationDecl>(D))
+ return canonicalRenameDecl(
+ VarTemplate->getSpecializedTemplate()->getTemplatedDecl());
+ if (const auto *Template = dyn_cast<TemplateDecl>(D))
+ if (const NamedDecl *TemplatedDecl = Template->getTemplatedDecl())
+ return canonicalRenameDecl(TemplatedDecl);
+ if (const auto *ClassTemplateSpecialization =
+ dyn_cast<ClassTemplateSpecializationDecl>(D))
+ return canonicalRenameDecl(
+ ClassTemplateSpecialization->getSpecializedTemplate()
+ ->getTemplatedDecl());
+ if (const auto *Method = dyn_cast<CXXMethodDecl>(D)) {
+ if (Method->getDeclKind() == Decl::Kind::CXXConstructor ||
+ Method->getDeclKind() == Decl::Kind::CXXDestructor)
+ return canonicalRenameDecl(Method->getParent());
+ if (const FunctionDecl *InstantiatedMethod =
+ Method->getInstantiatedFromMemberFunction())
+ Method = cast<CXXMethodDecl>(InstantiatedMethod);
+ // FIXME(kirillbobyrev): For virtual methods with
+ // size_overridden_methods() > 1, this will not rename all functions it
+ // overrides, because this code assumes there is a single canonical
+ // declaration.
+ while (Method->isVirtual() && Method->size_overridden_methods())
+ Method = *Method->overridden_methods().begin();
+ return dyn_cast<NamedDecl>(Method->getCanonicalDecl());
+ }
+ if (const auto *Function = dyn_cast<FunctionDecl>(D))
+ if (const FunctionTemplateDecl *Template = Function->getPrimaryTemplate())
+ return canonicalRenameDecl(Template);
+ return dyn_cast<NamedDecl>(D->getCanonicalDecl());
+}
+
llvm::DenseSet<const NamedDecl *> locateDeclAt(ParsedAST &AST,
SourceLocation TokenStartLoc) {
unsigned Offset =
for (const NamedDecl *D :
targetDecl(SelectedNode->ASTNode,
DeclRelation::Alias | DeclRelation::TemplatePattern)) {
- // Get to CXXRecordDecl from constructor or destructor.
- D = tooling::getCanonicalSymbolDeclaration(D);
- Result.insert(D);
+ Result.insert(canonicalRenameDecl(D));
}
return Result;
}
std::vector<SourceLocation> findOccurrencesWithinFile(ParsedAST &AST,
const NamedDecl &ND) {
trace::Span Tracer("FindOccurrencesWithinFile");
- // If the cursor is at the underlying CXXRecordDecl of the
- // ClassTemplateDecl, ND will be the CXXRecordDecl. In this case, we need to
- // get the primary template manually.
- // getUSRsForDeclaration will find other related symbols, e.g. virtual and its
- // overriddens, primary template and all explicit specializations.
- // FIXME: Get rid of the remaining tooling APIs.
- const auto *RenameDecl =
- ND.getDescribedTemplate() ? ND.getDescribedTemplate() : &ND;
- std::vector<std::string> RenameUSRs =
- tooling::getUSRsForDeclaration(RenameDecl, AST.getASTContext());
- llvm::DenseSet<SymbolID> TargetIDs;
- for (auto &USR : RenameUSRs)
- TargetIDs.insert(SymbolID(USR));
+ assert(canonicalRenameDecl(&ND) == &ND &&
+ "ND should be already canonicalized.");
std::vector<SourceLocation> Results;
for (Decl *TopLevelDecl : AST.getLocalTopLevelDecls()) {
if (Ref.Targets.empty())
return;
for (const auto *Target : Ref.Targets) {
- auto ID = getSymbolID(Target);
- if (!ID || TargetIDs.find(ID) == TargetIDs.end())
+ if (canonicalRenameDecl(Target) == &ND) {
+ Results.push_back(Ref.NameLoc);
return;
+ }
}
- Results.push_back(Ref.NameLoc);
});
}
return makeError(ReasonToReject::NoSymbolFound);
if (DeclsUnderCursor.size() > 1)
return makeError(ReasonToReject::AmbiguousSymbol);
- const auto &RenameDecl =
- llvm::cast<NamedDecl>(*(*DeclsUnderCursor.begin())->getCanonicalDecl());
+ const auto &RenameDecl = **DeclsUnderCursor.begin();
if (RenameDecl.getName() == RInputs.NewName)
return makeError(ReasonToReject::SameName);
auto Invalid = checkName(RenameDecl, RInputs.NewName);