]> granicus.if.org Git - clang/commitdiff
Introduce redecl_iterator, used for iterating over the redeclarations of a FunctionDe...
authorArgyrios Kyrtzidis <akyrtzi@gmail.com>
Tue, 14 Jul 2009 03:20:21 +0000 (03:20 +0000)
committerArgyrios Kyrtzidis <akyrtzi@gmail.com>
Tue, 14 Jul 2009 03:20:21 +0000 (03:20 +0000)
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

include/clang/AST/Decl.h
lib/AST/Decl.cpp

index 7f121ba083d28e09b26473b13b3f83f2df711d75..66099217b06840d241f2a2e7bc5163a94e16757a 100644 (file)
@@ -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<VarDecl*>(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<FunctionDecl*>(this));
+  }
+  redecl_iterator redecls_end() const { return redecl_iterator(); }
+
   unsigned getBuiltinID(ASTContext &Context) const;
 
   unsigned getNumParmVarDeclsFromType() const;
index ae1df920125dc66ff2a2851d3e918b63e3fe2f66..19f17184185352bc448c7d929390e67c78145ef0 100644 (file)
@@ -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<GNUInlineAttr>())
     return false;
 
-  for (const FunctionDecl *FD = getPreviousDeclaration(); FD; 
-       FD = FD->getPreviousDeclaration()) {
-    if (FD->isInline() && !FD->hasAttr<GNUInlineAttr>())
+  for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I)
+    if (I->isInline() && !I->hasAttr<GNUInlineAttr>())
       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<GNUInlineAttr>())
+  for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I)
+    if (I->getStorageClass() == Extern && I->hasAttr<GNUInlineAttr>())
       return true;
 
   return false;