// Get the USRs for the constructors of the class. static std::vector<std::string> getAllConstructorUSRs( const CXXRecordDecl *Decl) { std::vector<std::string> USRs; // We need to get the definition of the record (as opposed to any forward // declarations) in order to find the constructor and destructor. const auto *RecordDecl = Decl->getDefinition(); // Iterate over all the constructors and add their USRs. for (const auto *CtorDecl : RecordDecl->ctors()) USRs.push_back(getUSRForDecl(CtorDecl)); // Ignore destructors. GetLocationsOfUSR will find the declaration of and // explicit calls to a destructor through TagTypeLoc (and it is better for the // purpose of renaming). // // For example, in the following code segment, // 1 class C { // 2 ~C(); // 3 }; // At line 3, there is a NamedDecl starting from '~' and a TagTypeLoc starting // from 'C'. return USRs; }
static void populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D, const FullComment *FC, int LineNumber, StringRef Filename) { populateSymbolInfo(I, D, FC, LineNumber, Filename); if (const auto *T = getDeclForType(D->getReturnType())) { if (dyn_cast<EnumDecl>(T)) I.ReturnType = TypeInfo(getUSRForDecl(T), T->getNameAsString(), InfoType::IT_enum); else if (dyn_cast<RecordDecl>(T)) I.ReturnType = TypeInfo(getUSRForDecl(T), T->getNameAsString(), InfoType::IT_record); } else { I.ReturnType = TypeInfo(D->getReturnType().getAsString()); } parseParameters(I, D); }
static void parseParameters(FunctionInfo &I, const FunctionDecl *D) { for (const ParmVarDecl *P : D->parameters()) { if (const auto *T = getDeclForType(P->getOriginalType())) { if (const auto *N = dyn_cast<EnumDecl>(T)) { I.Params.emplace_back(getUSRForDecl(N), N->getNameAsString(), InfoType::IT_enum, P->getNameAsString()); continue; } else if (const auto *N = dyn_cast<RecordDecl>(T)) { I.Params.emplace_back(getUSRForDecl(N), N->getNameAsString(), InfoType::IT_record, P->getNameAsString()); continue; } } I.Params.emplace_back(P->getOriginalType().getAsString(), P->getNameAsString()); } }
static void populateInfo(Info &I, const T *D, const FullComment *C) { I.USR = getUSRForDecl(D); I.Name = D->getNameAsString(); populateParentNamespaces(I.Namespace, D); if (C) { I.Description.emplace_back(); parseFullComment(C, I.Description.back()); } }
static void populateParentNamespaces(llvm::SmallVector<Reference, 4> &Namespaces, const T *D) { const auto *DC = dyn_cast<DeclContext>(D); while ((DC = DC->getParent())) { if (const auto *N = dyn_cast<NamespaceDecl>(DC)) Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(), InfoType::IT_namespace); else if (const auto *N = dyn_cast<RecordDecl>(DC)) Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(), InfoType::IT_record); else if (const auto *N = dyn_cast<FunctionDecl>(DC)) Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(), InfoType::IT_function); else if (const auto *N = dyn_cast<EnumDecl>(DC)) Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(), InfoType::IT_enum); } }
static void parseBases(RecordInfo &I, const CXXRecordDecl *D) { // Don't parse bases if this isn't a definition. if (!D->isThisDeclarationADefinition()) return; for (const CXXBaseSpecifier &B : D->bases()) { if (B.isVirtual()) continue; if (const auto *P = getDeclForType(B.getType())) I.Parents.emplace_back(getUSRForDecl(P), P->getNameAsString(), InfoType::IT_record); else I.Parents.emplace_back(B.getType().getAsString()); } for (const CXXBaseSpecifier &B : D->vbases()) { if (const auto *P = getDeclForType(B.getType())) I.VirtualParents.emplace_back(getUSRForDecl(P), P->getNameAsString(), InfoType::IT_record); else I.VirtualParents.emplace_back(B.getType().getAsString()); } }
static void parseFields(RecordInfo &I, const RecordDecl *D, bool PublicOnly) { for (const FieldDecl *F : D->fields()) { if (PublicOnly && !isPublic(F->getAccessUnsafe(), F->getLinkageInternal())) continue; if (const auto *T = getDeclForType(F->getTypeSourceInfo()->getType())) { // Use getAccessUnsafe so that we just get the default AS_none if it's not // valid, as opposed to an assert. if (const auto *N = dyn_cast<EnumDecl>(T)) { I.Members.emplace_back(getUSRForDecl(T), N->getNameAsString(), InfoType::IT_enum, F->getNameAsString(), N->getAccessUnsafe()); continue; } else if (const auto *N = dyn_cast<RecordDecl>(T)) { I.Members.emplace_back(getUSRForDecl(T), N->getNameAsString(), InfoType::IT_record, F->getNameAsString(), N->getAccessUnsafe()); continue; } } I.Members.emplace_back(F->getTypeSourceInfo()->getType().getAsString(), F->getNameAsString(), F->getAccessUnsafe()); } }
std::unique_ptr<Info> emitInfo(const CXXMethodDecl *D, const FullComment *FC, int LineNumber, llvm::StringRef File, bool PublicOnly) { if (PublicOnly && !isPublic(D->getAccess(), D->getLinkageInternal())) return nullptr; FunctionInfo Func; populateFunctionInfo(Func, D, FC, LineNumber, File); Func.IsMethod = true; SymbolID ParentUSR = getUSRForDecl(D->getParent()); Func.Parent = Reference{ParentUSR, D->getParent()->getNameAsString(), InfoType::IT_record}; Func.Access = D->getAccess(); // Wrap in enclosing scope auto I = llvm::make_unique<RecordInfo>(); I->USR = ParentUSR; I->ChildFunctions.emplace_back(std::move(Func)); return std::unique_ptr<Info>{std::move(I)}; }
void HandleTranslationUnit(ASTContext &Context) override { const auto &SourceMgr = Context.getSourceManager(); // The file we look for the USR in will always be the main source file. const auto Point = SourceMgr.getLocForStartOfFile( SourceMgr.getMainFileID()).getLocWithOffset(SymbolOffset); if (!Point.isValid()) return; const NamedDecl *FoundDecl = nullptr; if (OldName.empty()) { FoundDecl = getNamedDeclAt(Context, Point); } else { FoundDecl = getNamedDeclFor(Context, OldName); } if (FoundDecl == nullptr) { FullSourceLoc FullLoc(Point, SourceMgr); errs() << "clang-rename: could not find symbol at " << SourceMgr.getFilename(Point) << ":" << FullLoc.getSpellingLineNumber() << ":" << FullLoc.getSpellingColumnNumber() << " (offset " << SymbolOffset << ").\n"; return; } // If the decl is a constructor or destructor, we want to instead take the // decl of the parent record. if (const auto *CtorDecl = dyn_cast<CXXConstructorDecl>(FoundDecl)) FoundDecl = CtorDecl->getParent(); else if (const auto *DtorDecl = dyn_cast<CXXDestructorDecl>(FoundDecl)) FoundDecl = DtorDecl->getParent(); // If the decl is in any way relatedpp to a class, we want to make sure we // search for the constructor and destructor as well as everything else. if (const auto *Record = dyn_cast<CXXRecordDecl>(FoundDecl)) *USRs = getAllConstructorUSRs(Record); USRs->push_back(getUSRForDecl(FoundDecl)); *SpellingName = FoundDecl->getNameAsString(); }