Skip to content
Snippets Groups Projects
Forked from pub / Frama Clang
541 commits behind the upstream repository.
VisitTable.h 22.89 KiB
/**************************************************************************/
/*                                                                        */
/*  This file is part of Frama-Clang                                      */
/*                                                                        */
/*  Copyright (C) 2012-2020                                               */
/*    CEA (Commissariat à l'énergie atomique et aux énergies              */
/*         alternatives)                                                  */
/*                                                                        */
/*  you can redistribute it and/or modify it under the terms of the GNU   */
/*  Lesser General Public License as published by the Free Software       */
/*  Foundation, version 2.1.                                              */
/*                                                                        */
/*  It is distributed in the hope that it will be useful,                 */
/*  but WITHOUT ANY WARRANTY; without even the implied warranty of        */
/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         */
/*  GNU Lesser General Public License for more details.                   */
/*                                                                        */
/*  See the GNU Lesser General Public License version 2.1                 */
/*  for more details (enclosed in the file LICENSE).                      */
/*                                                                        */
/**************************************************************************/

//
// Description:
//   Definition of VisitTable
//

#ifndef Visit_TableH
#define Visit_TableH

#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wclass-memaccess"
#endif
#include "clang/AST/DeclCXX.h"
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif

#include "Clang_utils.h"

extern "C" {
#include "intermediate_format.h"
}

class VisitTable {
public:
  class KeyInfo {
  private:
    const clang::Decl* _key;
    friend class VisitTable;

  public:
    KeyInfo(const clang::Decl* key) : _key(key) {}
    KeyInfo(const KeyInfo& source) : _key(source._key) {}
    virtual ~KeyInfo() {}
    virtual bool isSubKey() const { return false; }
    virtual bool isMissingDecl() const { return false; }
    virtual bool isGenerationMissing() const { return false; }
    virtual bool isClassGenerationMissing() const { return false; }
    virtual bool isInstanceClass() const { return false; }
    virtual bool isFunctionGenerationMissing() const { return false; }
    virtual bool replaceWaitingBy(const clang::Decl* oldDecl,
        const std::vector<const clang::Decl*>& newDecls)
      { assert(false); return true; }
    virtual bool solve(const clang::Decl* decl, ForwardReferenceList& globals,
        VisitTable& table) { assert(false); return false; }
    virtual bool isComplete() const { return true; }
    virtual void print(std::ostream& out) const
      { const clang::NamedDecl* decl = llvm::dyn_cast<clang::NamedDecl>
            (_key);
        if (decl)
          out << decl->getNameAsString() << ": ";
        else
          out << "clang_unnamed: ";
      }
    const clang::Decl* key() const { return _key; }

    class Less {
    public:
      bool operator()(const KeyInfo* first, const KeyInfo* second) const
        { return first->_key < second->_key; }
    };
  };

  class SubKeyInfo : public KeyInfo {
  private:
    const clang::Decl* _root;
    std::vector<const clang::Decl*> _specificWaitDeclarations;

  public:
    SubKeyInfo(const clang::Decl* key, const clang::Decl* root,
        std::vector<const clang::Decl*>& specificWaitDeclarations)
      : KeyInfo(key), _root(root)
      { _specificWaitDeclarations.swap(specificWaitDeclarations); }
    SubKeyInfo(const clang::Decl* key, const clang::Decl* root)
      : KeyInfo(key), _root(root) {}
    SubKeyInfo(const SubKeyInfo& source)
      : KeyInfo(source), _root(source._root),
        _specificWaitDeclarations(source._specificWaitDeclarations) {}

    virtual bool isSubKey() const { return true; }
    const clang::Decl* root() const { return _root; }
    const std::vector<const clang::Decl*>& getSpecificWaitDeclarations() const
      { return _specificWaitDeclarations; }
    void addSpecificWaitDeclarations(
        const std::vector<const clang::Decl*>& waitDeclarations)
      { if (!waitDeclarations.empty()) {
          if (_specificWaitDeclarations.empty())
            _specificWaitDeclarations = waitDeclarations;
          else {
            std::vector<const clang::Decl*>::const_iterator
              sourceIterEnd = waitDeclarations.end(),
              sourceIter = waitDeclarations.begin();
            for (; sourceIter != sourceIterEnd; ++sourceIter) {
              const clang::Decl* declToInsert = *sourceIter;
              bool hasFound = false;
              std::vector<const clang::Decl*>::const_iterator
                iterEnd = _specificWaitDeclarations.end(),
                iter = _specificWaitDeclarations.begin();
              for (; !hasFound && iter != iterEnd; ++iter)
                hasFound = *iter == declToInsert;
              if (!hasFound)
                _specificWaitDeclarations.push_back(declToInsert);
            };
          };
        };
      }
  };

  class MissingFunctionGeneration : public KeyInfo {
  private:
    translation_unit_decl _waitingFunDefinition;
    translation_unit_decl _waitingAdditionalFunDefinition; /* may be NULL */
    std::vector<const clang::Decl*> _waitDeclarations;
    friend class VisitTable;

  public:
    MissingFunctionGeneration(const clang::FunctionDecl* key,
        translation_unit_decl waitingDefinition,
        translation_unit_decl waitingAdditionalDefinition=NULL)
      : KeyInfo(key), _waitingFunDefinition(waitingDefinition),
        _waitingAdditionalFunDefinition(waitingAdditionalDefinition) {}
    virtual ~MissingFunctionGeneration()
      { if (_waitingFunDefinition) {
          free_translation_unit_decl(_waitingFunDefinition);
          _waitingFunDefinition = NULL;
        };
        if (_waitingAdditionalFunDefinition) {
          free_translation_unit_decl(_waitingAdditionalFunDefinition);
          _waitingAdditionalFunDefinition = NULL;
        };
      }
    
    const std::vector<const clang::Decl*>& waitDeclarations() const
      { return _waitDeclarations; }
    virtual bool isComplete() const
      { return !_waitingFunDefinition && _waitDeclarations.empty(); }
    virtual void print(std::ostream& out) const;
    virtual bool isGenerationMissing() const { return true; }
    virtual bool isFunctionGenerationMissing() const { return true; }
    virtual bool solve(const clang::Decl* decl, ForwardReferenceList& globals,
        VisitTable& table);
    virtual bool replaceWaitingBy(const clang::Decl* oldDecl,
        const std::vector<const clang::Decl*>& newDecls);
  };

  class MissingSubClassGeneration {
  private:
    const clang::Decl* _key;
    class_decl _waitingSubClassDecl;
    std::vector<const clang::Decl*> _additionalWaitDeclarations;
    std::vector<MissingSubClassGeneration> _subGenerations;
    std::set<const clang::Decl*> _subWaitDeclarations;
    int _parentPosition;
    friend class VisitTable;

  public:
    MissingSubClassGeneration(const clang::RecordDecl* key,
        class_decl waitingSubClassDecl, int parentPosition)
      : _key(key), _waitingSubClassDecl(waitingSubClassDecl),
        _parentPosition(parentPosition) {}

    void addWaitFor(const clang::Decl* decl)
      { _additionalWaitDeclarations.push_back(decl); }
    MissingSubClassGeneration& createSubDeclaration(
        const clang::RecordDecl* key, class_decl waitingSubClassDecl)
      { int position = 0;
        assert(_waitingSubClassDecl
          && _waitingSubClassDecl->tag_class_decl == CCOMPOUND
          && _waitingSubClassDecl->cons_class_decl.CCompound.body->is_some);
        /* class_decl */ list parentList = (list) _waitingSubClassDecl
          ->cons_class_decl.CCompound.body->content.container;
        while (parentList) {
          ++position;
          parentList = parentList->next;
        };
        _subGenerations.push_back(MissingSubClassGeneration(key,
            waitingSubClassDecl, position + _subGenerations.size()));
        return _subGenerations.back();
      }
    const std::vector<const clang::Decl*>& waitDeclarations() const
      { return _additionalWaitDeclarations; }
    std::vector<const clang::Decl*>& waitDeclarations()
      { return _additionalWaitDeclarations; }
    bool removeWait(const clang::Decl* decl);
    bool removeWaitWithinClass(const clang::Decl* decl,
        /* class_decl */ list*& cursor, /* class_decl */ list* parentDeclList,
        int& cursorIndex, int targetIndex)
      { assert(_waitingSubClassDecl
          && _waitingSubClassDecl->tag_class_decl == CCOMPOUND
          && _waitingSubClassDecl->cons_class_decl.CCompound.body->is_some);
        class_decl subContent = _waitingSubClassDecl;
        bool result = removeWait(decl);
        if (result) {
          assert(targetIndex >= 0);
          if (cursor == NULL || cursorIndex > targetIndex) {
            cursor = parentDeclList;
            cursorIndex = 0;
          }
          while (cursorIndex < targetIndex) {
            ++cursorIndex;
            cursor = &(*cursor)->next;
          }
          list next = *cursor;
          *cursor = cons_container(subContent, next);
        };
        return result;
      }
#if 0
    bool solve(const clang::Decl* decl, MissingClassGeneration& parentDecl,
        ForwardReferenceList& globals, VisitTable& table);
#endif
    void print(std::ostream& out, bool ident=1) const;
    bool replaceWaitingBy(const clang::Decl* oldDecl,
        const std::vector<const clang::Decl*>& newDecls);
    class_decl getWaitingSubClassDecl() const { return _waitingSubClassDecl; }
    bool setAsComplete(ForwardReferenceList& classDeclList)
      { assert(_waitingSubClassDecl);
        bool result;
        if (_additionalWaitDeclarations.empty()) {
          classDeclList.insertContainer(_waitingSubClassDecl);
          _waitingSubClassDecl = NULL;
          result = true;
        }
        else
          result = false;
        if (!_subGenerations.empty()) {
          std::vector<MissingSubClassGeneration>::const_iterator
            subIterEnd=_subGenerations.end(), subIter=_subGenerations.begin();
          for (; subIter != subIterEnd; ++subIter) {
            _subWaitDeclarations.insert(subIter->_additionalWaitDeclarations.begin(),
              subIter->_additionalWaitDeclarations.end());
            _subWaitDeclarations.insert(subIter->_subWaitDeclarations.begin(),
              subIter->_subWaitDeclarations.end());
          };
        };
        return result;
      }
    /* class_decl */ list& getContent() const
      { assert(_waitingSubClassDecl->tag_class_decl==CCOMPOUND);
        return *(/* class_decl */ list*) &_waitingSubClassDecl
          ->cons_class_decl.CCompound.body->content.container;
      }
    const clang::Decl* key() const { return _key; }
    const std::vector<const clang::Decl*>* findSubClassDependencies(
        const clang::Decl* subClass) const
      { const std::vector<const clang::Decl*>* result = NULL;
        std::vector<MissingSubClassGeneration>::const_iterator
          subIter = _subGenerations.begin(), subIterEnd = _subGenerations.end();
        for (; !result && subIter != subIterEnd; ++subIter) {
          if (subIter->_key == subClass)
            result = &subIter->_additionalWaitDeclarations;
          else
            result = subIter->findSubClassDependencies(subClass);
        };
        return result;  
      }
  };
  class MissingClassGeneration : public KeyInfo {
  private:
    translation_unit_decl _waitingClassDeclaration;
    std::vector<const clang::Decl*> _waitDeclarations;
    std::vector<MissingSubClassGeneration> _subGenerations;
    std::set<const clang::Decl*> _subWaitDeclarations;
    friend class VisitTable;

  public:
    MissingClassGeneration(const clang::RecordDecl* key,
        translation_unit_decl waitingDeclaration)
      : KeyInfo(key), _waitingClassDeclaration(waitingDeclaration) {}
    MissingClassGeneration(const MissingClassGeneration& source)
      : KeyInfo(source),
        _waitingClassDeclaration(source._waitingClassDeclaration)
      { const_cast<MissingClassGeneration&>(source)
            ._waitingClassDeclaration = NULL;
        _waitDeclarations.swap(const_cast<MissingClassGeneration&>(
            source)._waitDeclarations);
        _subGenerations.swap(const_cast<MissingClassGeneration&>(
            source)._subGenerations);
        _subWaitDeclarations.swap(const_cast<MissingClassGeneration&>(
            source)._subWaitDeclarations);
      }
    virtual ~MissingClassGeneration()
      { if (_waitingClassDeclaration) {
          free_translation_unit_decl(_waitingClassDeclaration);
          _waitingClassDeclaration = NULL;
        };
      }
    MissingSubClassGeneration& createSubDeclaration(
        const clang::RecordDecl* key, class_decl waitingSubClassDecl)
      { int position = 0;
        assert(_waitingClassDeclaration
          && _waitingClassDeclaration->tag_translation_unit_decl == COMPOUND
          && _waitingClassDeclaration->cons_translation_unit_decl.Compound
            .body->is_some);
        /* class_decl */ list parentList = (list) _waitingClassDeclaration
          ->cons_translation_unit_decl.Compound.body->content.container;
        while (parentList) {
          ++position;
          parentList = parentList->next;
        };
        _subGenerations.push_back(MissingSubClassGeneration(key,
            waitingSubClassDecl, position + _subGenerations.size()));
        return _subGenerations.back();
      }
    std::vector<const clang::Decl*>& waitDeclarations()
      { return _waitDeclarations; }
    const std::vector<const clang::Decl*>& waitDeclarations() const
      { return _waitDeclarations; }
    const std::set<const clang::Decl*>& subWaitDeclarations() const
      { return _subWaitDeclarations; }
    translation_unit_decl getWaitingClassDeclaration() const
      { return _waitingClassDeclaration; }
    const std::vector<const clang::Decl*>* findSubClassDependencies(
        const clang::Decl* subClass) const
      { const std::vector<const clang::Decl*>* result = NULL;
        std::vector<MissingSubClassGeneration>::const_iterator
          subIter = _subGenerations.begin(), subIterEnd = _subGenerations.end();
        for (; !result && subIter != subIterEnd; ++subIter) {
          if (subIter->key() == subClass)
            result = &subIter->waitDeclarations();
          else
            result = subIter->findSubClassDependencies(subClass);
        };
        return result;  
      }

    virtual bool isClassGenerationMissing() const { return true; }
    virtual bool isGenerationMissing() const { return true; }
    virtual bool isComplete() const
      { return !_waitingClassDeclaration && _waitDeclarations.empty()
          && _subGenerations.empty() && _subWaitDeclarations.empty();
      }
    virtual void print(std::ostream& out) const;
    virtual bool solve(const clang::Decl* decl, ForwardReferenceList& globals,
        VisitTable& table);
    virtual bool replaceWaitingBy(const clang::Decl* oldDecl,
        const std::vector<const clang::Decl*>& newDecls);
    void removeSubWait(const clang::Decl* decl);
    /* class_decl */ list& getContent() const
      { assert(_waitingClassDeclaration->tag_translation_unit_decl==COMPOUND);
        return *(/* class_decl */ list*) &_waitingClassDeclaration
          ->cons_translation_unit_decl.Compound.body->content.container;
      }
  };

  class InstanceClassGeneration : public MissingClassGeneration {
  public:
    typedef std::vector<KeyInfo*> WaitingDecls;

  private:
    WaitingDecls _waitingDecls;
    friend class VisitTable;

  public:
    InstanceClassGeneration(const clang::RecordDecl* key,
        translation_unit_decl waitingDeclaration)
      : MissingClassGeneration(key, waitingDeclaration) {}

    virtual void print(std::ostream& out) const { assert(false); }
    virtual bool isInstanceClass() const { return true; }
    virtual bool solve(const clang::Decl* decl, ForwardReferenceList& globals,
        VisitTable& table) { assert(false); return false; }
  };

  class MissingDecl : public KeyInfo {
  public:
    typedef std::vector<KeyInfo*> WaitingDecls;

  private:
    WaitingDecls _waitingDecls;
    friend class VisitTable;

  public:
    MissingDecl(const clang::Decl* decl) : KeyInfo(decl) {}
    virtual bool isMissingDecl() const { return true; }
    virtual bool isComplete() const { return false /* _waitingDecls.empty() */;}

    WaitingDecls& waitingDecls() { return _waitingDecls; }
    virtual void print(std::ostream& out) const;
  };

private:
  typedef std::set<KeyInfo*, KeyInfo::Less> ContentTable;
  typedef std::map<const clang::FunctionDecl*, std::list<bool*> >
    UpdateFunctionDeclarations;
 
  Clang_utils* _clangUtils;
  ContentTable _content;
  UpdateFunctionDeclarations _updateFunctionDeclarations;

protected:
  void solve(MissingSubClassGeneration& classDecl,
      MissingClassGeneration& rootDecl, ForwardReferenceList& globals);
  void addWaitFor(MissingSubClassGeneration& classDecl,
      class_decl classElement, MissingClassGeneration* parentDecl,
      ForwardReferenceList& globals, bool shouldBeSubkey=false);
  friend class MissingSubClassGeneration;
  friend class MissingClassGeneration;

  void enableNotificationFromBeforeReplaceWaiting(
      std::vector<const clang::Decl*>& dependencies,
      const std::vector<KeyInfo*>& waitingDecls, KeyInfo* originDependencies,
      bool mayHaveInstanceClass);

public:
  VisitTable() : _clangUtils(NULL) {}
  ~VisitTable()
    { ContentTable::iterator iterEnd = _content.end();
      for (ContentTable::iterator iter = _content.begin();
          iter != iterEnd; ++iter)
        if (*iter) delete *iter;
      _content.clear();
    }
  void setUtils(Clang_utils* clangUtils) { _clangUtils = clangUtils; }
  bool isComplete() const
    { ContentTable::iterator iterEnd = _content.end();
      for (ContentTable::iterator iter = _content.begin();
          iter != iterEnd; ++iter)
        if (!(*iter)->isComplete())
          return false;
      return true;
    }
  void printIncompleteDeclarations(std::ostream& out) const
    { ContentTable::iterator iterEnd = _content.end(), iter = _content.begin();
      while (iter != iterEnd) {
        if (!(*iter)->isComplete()) {
          (*iter)->print(out);
          out << '\n';
        };
        ++iter;
      };
    }
  void addDeclaration(const clang::Decl* decl, ForwardReferenceList& globals);
  void addFunctionDeclaration(const clang::FunctionDecl* decl,
    ForwardReferenceList& globals);
  void addSubDeclaration(const clang::Decl* decl, const clang::Decl* root,
      MissingSubClassGeneration* lastInstance /* should be a stack */,
      ForwardReferenceList& globals);

  bool hasVisited(const clang::Decl* decl,
      std::vector<const clang::Decl*>* alternativeDecls = NULL) const
    { KeyInfo locateKey(decl);
      ContentTable::const_iterator found = _content.find(&locateKey);
      bool result = false;
      if (found != _content.end()) {
         if (!(*found)->isMissingDecl()) {
           if (alternativeDecls && (*found)->isSubKey()
               && !((const SubKeyInfo&) **found).getSpecificWaitDeclarations()
                  .empty())
             *alternativeDecls = ((const SubKeyInfo&) **found)
               .getSpecificWaitDeclarations();
           else
             result = true;
         }
      };
      return result;
    }
  bool hasGenerated(const clang::Decl* decl) const
    { KeyInfo locateKey(decl);
      ContentTable::const_iterator found = _content.find(&locateKey);
      return (found != _content.end()) && !(*found)->isMissingDecl()
          && !(*found)->isGenerationMissing();
    }
  void ensureGeneration(const clang::Decl* decl,
      std::vector<const clang::Decl*>& waitedDeclarations) const;
  translation_unit_decl globalizeDecl(const clang::NamedDecl* decl,
      class_decl classElement) const;
  MissingClassGeneration& addInstanceClass(const clang::RecordDecl* decl,
      translation_unit_decl classDecl);
  MissingSubClassGeneration& addSubClass(MissingClassGeneration& firstInstance,
      MissingSubClassGeneration* lastClass, const clang::RecordDecl* decl,
      class_decl classDecl)
    { VisitTable::MissingSubClassGeneration* result;
      if (!lastClass)
        result = &firstInstance.createSubDeclaration(decl, classDecl);
      else
        result = &lastClass->createSubDeclaration(decl, classDecl);
      return *result;
    }
  void setInstanceClassAsComplete(InstanceClassGeneration* instance,
    ForwardReferenceList& globals);
  void makeTemporaryUnvisited(const clang::RecordDecl* decl)
    { KeyInfo locateKey(decl);
      ContentTable::iterator found = _content.find(&locateKey);
      assert(found != _content.end() && (*found)->isComplete()
          && !(*found)->isMissingDecl() && !(*found)->isGenerationMissing());
      _content.erase(found);
      _content.insert(new MissingDecl(decl)); // MissingClassGeneration(decl, NULL)
    }
  void makeTemporaryVisited(const clang::RecordDecl* decl,
      ForwardReferenceList& globals)
    { addDeclaration(decl, globals); }

  MissingClassGeneration& addIncompleteClass(const clang::RecordDecl* decl,
      std::vector<const clang::Decl*>& waitDeclarations,
      translation_unit_decl classDecl);

  MissingFunctionGeneration& addIncompleteFunction(
      const clang::FunctionDecl* decl,
      std::vector<const clang::Decl*>& waitDeclarations,
      translation_unit_decl functionDecl,
      translation_unit_decl functionBareDecl = NULL/* may be NULL */);

  void addUpdateFunction(const clang::FunctionDecl* decl,
      bool* furtherDefinitionFlag)
  { const clang::FunctionDecl* can = decl->getCanonicalDecl();
    UpdateFunctionDeclarations::iterator found
      = _updateFunctionDeclarations.find(can);
    if (found == _updateFunctionDeclarations.end()) {
      std::list<bool*> updates;
      updates.push_back(furtherDefinitionFlag);
      _updateFunctionDeclarations.insert(std::make_pair(can, updates));
    }
    else {
      if (found->second.empty()) // we have seen a declaration with a contract.
        *furtherDefinitionFlag = true;
      else { 
        if (*found->second.front()) 
          // we have seen a declaration with a contract.
          *furtherDefinitionFlag = true;
        found->second.push_back(furtherDefinitionFlag);
      }
    };
  }

  void visitFunctionDefinitionWithContract(const clang::FunctionDecl* decl)
    { 
      const clang::FunctionDecl* can = decl->getCanonicalDecl();
      UpdateFunctionDeclarations::iterator found
        = _updateFunctionDeclarations.find(can);
      if (found == _updateFunctionDeclarations.end())
        _updateFunctionDeclarations.insert(
          std::make_pair(can, std::list<bool*>()));
      else {
        //assert(!found->second.empty());
        std::list<bool*>::iterator iterEnd = found->second.end();
        for (std::list<bool*>::iterator iter = found->second.begin();
            iter != iterEnd; ++iter)
          **iter = true;
        found->second.clear();
      };
    }
};

#endif // Visit_TableH