From: Argyrios Kyrtzidis Date: Tue, 14 Jul 2009 03:20:21 +0000 (+0000) Subject: Introduce redecl_iterator, used for iterating over the redeclarations of a FunctionDe... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c37929c9e0dba89770dc5f0fbcfa0c9046da0b06;p=clang Introduce redecl_iterator, used for iterating over the redeclarations of a FunctionDecl or VarDecl. It iterates over all the redeclarations, regardless of the starting point. For example: 1) int f(); 2) int f(); 3) int f(); if you have the (2) FunctionDecl and call redecls_begin/redecls_end to iterate, you'll get this sequence: (2) (1) (3) The motivation to introduce this was that, previously, if (3) was a function definition, and you called getBody() at (2), it would not return it, since getBody() iterated over the previous declarations only, so it would only check (2) and (1). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@75604 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 7f121ba083..66099217b0 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -439,6 +439,54 @@ public: virtual Decl *getPrimaryDecl() const; + /// \brief Iterates through all the redeclarations of the same var decl. + class redecl_iterator { + /// Current - The current declaration. + VarDecl *Current; + VarDecl *Starter; + + public: + typedef VarDecl* value_type; + typedef VarDecl* reference; + typedef VarDecl* pointer; + typedef std::forward_iterator_tag iterator_category; + typedef std::ptrdiff_t difference_type; + + redecl_iterator() : Current(0) { } + explicit redecl_iterator(VarDecl *C) : Current(C), Starter(C) { } + + reference operator*() const { return Current; } + pointer operator->() const { return Current; } + + redecl_iterator& operator++() { + assert(Current && "Advancing while iterator has reached end"); + // Get either previous decl or latest decl. + VarDecl *Next = Current->PreviousDeclaration.getPointer(); + Current = (Next != Starter ? Next : 0); + return *this; + } + + redecl_iterator operator++(int) { + redecl_iterator tmp(*this); + ++(*this); + return tmp; + } + + friend bool operator==(redecl_iterator x, redecl_iterator y) { + return x.Current == y.Current; + } + friend bool operator!=(redecl_iterator x, redecl_iterator y) { + return x.Current != y.Current; + } + }; + + /// \brief Returns iterator for all the redeclarations of the same variable. + /// It will iterate at least once (when this decl is the only one). + redecl_iterator redecls_begin() const { + return redecl_iterator(const_cast(this)); + } + redecl_iterator redecls_end() const { return redecl_iterator(); } + /// hasLocalStorage - Returns true if a variable with function scope /// is a non-static local variable. bool hasLocalStorage() const { @@ -862,6 +910,54 @@ public: virtual Decl *getPrimaryDecl() const; + /// \brief Iterates through all the redeclarations of the same function decl. + class redecl_iterator { + /// Current - The current declaration. + FunctionDecl *Current; + FunctionDecl *Starter; + + public: + typedef FunctionDecl* value_type; + typedef FunctionDecl* reference; + typedef FunctionDecl* pointer; + typedef std::forward_iterator_tag iterator_category; + typedef std::ptrdiff_t difference_type; + + redecl_iterator() : Current(0) { } + explicit redecl_iterator(FunctionDecl *C) : Current(C), Starter(C) { } + + reference operator*() const { return Current; } + pointer operator->() const { return Current; } + + redecl_iterator& operator++() { + assert(Current && "Advancing while iterator has reached end"); + // Get either previous decl or latest decl. + FunctionDecl *Next = Current->PreviousDeclaration.getPointer(); + Current = (Next != Starter ? Next : 0); + return *this; + } + + redecl_iterator operator++(int) { + redecl_iterator tmp(*this); + ++(*this); + return tmp; + } + + friend bool operator==(redecl_iterator x, redecl_iterator y) { + return x.Current == y.Current; + } + friend bool operator!=(redecl_iterator x, redecl_iterator y) { + return x.Current != y.Current; + } + }; + + /// \brief Returns iterator for all the redeclarations of the same function + /// decl. It will iterate at least once (when this decl is the only one). + redecl_iterator redecls_begin() const { + return redecl_iterator(const_cast(this)); + } + redecl_iterator redecls_end() const { return redecl_iterator(); } + unsigned getBuiltinID(ASTContext &Context) const; unsigned getNumParmVarDeclsFromType() const; diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index ae1df92012..19f1718418 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -351,11 +351,15 @@ bool VarDecl::isTentativeDefinition(ASTContext &Context) const { } const Expr *VarDecl::getDefinition(const VarDecl *&Def) const { - Def = this; - while (Def && !Def->getInit()) - Def = Def->getPreviousDeclaration(); + redecl_iterator I = redecls_begin(), E = redecls_end(); + while (I != E && !I->getInit()) + ++I; - return Def? Def->getInit() : 0; + if (I != E) { + Def = *I; + return I->getInit(); + } + return 0; } void VarDecl::setPreviousDeclaration(VarDecl *PrevDecl) { @@ -405,11 +409,10 @@ void FunctionDecl::Destroy(ASTContext& C) { Stmt *FunctionDecl::getBody(const FunctionDecl *&Definition) const { - for (const FunctionDecl *FD = this; - FD != 0; FD = FD->getPreviousDeclaration()) { - if (FD->Body) { - Definition = FD; - return FD->Body.get(getASTContext().getExternalSource()); + for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) { + if (I->Body) { + Definition = *I; + return I->Body.get(getASTContext().getExternalSource()); } } @@ -417,10 +420,9 @@ Stmt *FunctionDecl::getBody(const FunctionDecl *&Definition) const { } Stmt *FunctionDecl::getBodyIfAvailable() const { - for (const FunctionDecl *FD = this; - FD != 0; FD = FD->getPreviousDeclaration()) { - if (FD->Body && !FD->Body.isOffset()) { - return FD->Body.get(0); + for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) { + if (I->Body && !I->Body.isOffset()) { + return I->Body.get(0); } } @@ -568,11 +570,9 @@ bool FunctionDecl::hasActiveGNUInlineAttribute(ASTContext &Context) const { if (!isInline() || !hasAttr()) return false; - for (const FunctionDecl *FD = getPreviousDeclaration(); FD; - FD = FD->getPreviousDeclaration()) { - if (FD->isInline() && !FD->hasAttr()) + for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) + if (I->isInline() && !I->hasAttr()) return false; - } return true; } @@ -581,8 +581,8 @@ bool FunctionDecl::isExternGNUInline(ASTContext &Context) const { if (!hasActiveGNUInlineAttribute(Context)) return false; - for (const FunctionDecl *FD = this; FD; FD = FD->getPreviousDeclaration()) - if (FD->getStorageClass() == Extern && FD->hasAttr()) + for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) + if (I->getStorageClass() == Extern && I->hasAttr()) return true; return false;