-------------------------------------------------------------------------------
-- (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.Walk_Expression_P.Wf_Primary)
function Protected_References_By (Sym   : Dictionary.Symbol;
                                  Scope : Dictionary.Scopes) return Dictionary.Symbol is
   Result      : Dictionary.Symbol := Dictionary.NullSymbol;
   Current_Var : Dictionary.Symbol;
   It          : Dictionary.Iterator;

   function Is_Local_Protected_State (Var_Sym : Dictionary.Symbol;
                                      Scope   : Dictionary.Scopes) return Boolean
   --# global in Dictionary.Dict;
   -- pre IsOwnVariable (Var_Sym) and GetOwnVariableProtected (Var_Sym)
   -- returns True if the owner of Var_Sym is the protected type which also encloses the
   -- scope we are making the function call in
   is
      Compilation_Unit : Dictionary.Symbol;

      function Get_Enclosing_Package_Or_Protected_Type (Scope : Dictionary.Scopes) return Dictionary.Symbol
      --# global in Dictionary.Dict;
      is
         Current : Dictionary.Scopes;
         Region  : Dictionary.Symbol;
      begin
         Current := Scope;
         loop
            Region := Dictionary.GetRegion (Current);
            exit when Dictionary.IsPackage (Region);
            exit when Dictionary.IsProtectedType (Region);
            Current := Dictionary.GetEnclosingScope (Current);
         end loop;
         return Region;
      end Get_Enclosing_Package_Or_Protected_Type;

   begin -- Is_Local_Protected_State
      Compilation_Unit := Get_Enclosing_Package_Or_Protected_Type (Scope => Scope);
      return Dictionary.IsProtectedType (Compilation_Unit)
        and then Dictionary.IsTypeMark (Dictionary.GetOwner (Var_Sym))
        and then Dictionary.Types_Are_Equal
        (Left_Symbol        => Dictionary.GetOwner (Var_Sym),
         Right_Symbol       => Compilation_Unit,
         Full_Range_Subtype => False);
   end Is_Local_Protected_State;

begin -- Protected_References_By
   if Dictionary.IsAdaFunction (Sym) then -- IsAdaFunction used to block proof functions
      It := Dictionary.FirstGlobalVariable (Dictionary.IsAbstract, Sym);
      while not Dictionary.IsNullIterator (It) loop
         Current_Var := Dictionary.CurrentSymbol (It);
         if Dictionary.IsOwnVariable (Current_Var)
           and then Dictionary.GetOwnVariableProtected (Current_Var)
           and then not Dictionary.IsOwnVariableOrConstituentWithMode (Current_Var)
           and then not Is_Local_Protected_State (Var_Sym => Current_Var,
                                                  Scope   => Scope) then
            Result := Sym;
            exit;
         end if;
         It := Dictionary.NextSymbol (It);
      end loop;
   else -- check for pragma atomic protected variable case
      if Dictionary.IsOwnVariable (Sym)
        and then Dictionary.GetOwnVariableProtected (Sym)
        and then not Dictionary.IsOwnVariableOrConstituentWithMode (Sym) then
         Result := Sym;
      end if;
   end if;
   return Result;
end Protected_References_By;
