-------------------------------------------------------------------------------
-- (C) Altran Praxis Limited
-------------------------------------------------------------------------------
--
-- The SPARK toolset is free software; you can redistribute it and/or modify it
-- under terms of the GNU General Public License as published by the Free
-- Software Foundation; either version 3, or (at your option) any later
-- version. The SPARK toolset 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 General
-- Public License for more details. You should have received a copy of the GNU
-- General Public License distributed with the SPARK toolset; see file
-- COPYING3. If not, go to http://www.gnu.org/licenses for a complete copy of
-- the license.
--
--=============================================================================

separate (Sem.CompUnit)
procedure Up_Wf_Protected_Body (Node  : in     STree.SyntaxNode;
                                Scope : in out Dictionary.Scopes) is
   Subprog_It         : Dictionary.Iterator;
   Virtual_Element_It : Dictionary.Iterator;
   Closing_Ident_Node : STree.SyntaxNode;
begin
   Closing_Ident_Node := Last_Sibling_Of (Start_Node => Child_Node (Current_Node => Node));
   -- ASSUME Closing_Ident_Node = identifier
   SystemErrors.RT_Assert
     (C       => Syntax_Node_Type (Node => Closing_Ident_Node) = SP_Symbols.identifier,
      Sys_Err => SystemErrors.Invalid_Syntax_Tree,
      Msg     => "Expect Closing_Ident_Node = identifier in Up_Wf_Protected_Body");

   -- run checks here to ensure that all declared subprograms have bodies
   Subprog_It := Dictionary.First_Visible_Subprogram (The_Package_Or_Type => Dictionary.GetRegion (Scope));
   while not Dictionary.IsNullIterator (Subprog_It) loop
      if not Dictionary.HasBody (Dictionary.CurrentSymbol (Subprog_It)) then
         ErrorHandler.Semantic_Error
           (Err_Num   => 996,
            Reference => ErrorHandler.No_Reference,
            Position  => Node_Position (Node => Closing_Ident_Node),
            Id_Str    => Dictionary.GetSimpleName (Dictionary.CurrentSymbol (Subprog_It)));
      end if;
      Subprog_It := Dictionary.NextSymbol (Subprog_It);
   end loop;

   -- Check all the virtual elements have been seen.
   Virtual_Element_It := Dictionary.FirstVirtualElement (Dictionary.GetRegion (Scope));
   while not Dictionary.IsNullIterator (Virtual_Element_It) loop
      if Dictionary.IsConcreteOwnVariable (Dictionary.CurrentSymbol (Virtual_Element_It))
        and then not Dictionary.VirtualElementSeenByOwner (Dictionary.CurrentSymbol (Virtual_Element_It)) then
         -- This variable appears in the protects property but is not used by the
         -- protected type. Don't output the error if the variable is abstract as
         -- there will have already been an error output in the refinement clause.
         ErrorHandler.Semantic_Error_Sym2
           (Err_Num   => 947,
            Reference => ErrorHandler.No_Reference,
            Position  => Node_Position (Node => Closing_Ident_Node),
            Sym       => Dictionary.CurrentSymbol (Virtual_Element_It),
            Sym2      => Dictionary.GetRegion (Scope),
            Scope     => Scope);
      end if;
      Virtual_Element_It := Dictionary.NextSymbol (Virtual_Element_It);
   end loop;

   -- step out to enclosing scope for continued tree walk
   Scope := Dictionary.GetEnclosingScope (Scope);
end Up_Wf_Protected_Body;
