------------------------------------------------------------------------------
--                                                                          --
--                          GNATCHECK COMPONENTS                            --
--                                                                          --
--                      G N A T C H E C K . R U L E S                       --
--                                                                          --
--                                 S p e c                                  --
--                                                                          --
--                     Copyright (C) 2004-2007, AdaCore                     --
--                                                                          --
-- GNATCHECK  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 2, or ( at your option)  any  later --
-- version.  GNATCHECK  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 GNAT; see file  COPYING. If --
-- not,  write to the  Free Software Foundation,  51 Franklin Street, Fifth --
-- Floor, Boston, MA 02110-1301, USA.                                       --
--                                                                          --
-- GNATCHECK is maintained by AdaCore (http://www.adacore.com).             --
--                                                                          --
------------------------------------------------------------------------------

--  This is the top of gnatcheck hierarchy that defines individual rules, rule
--  table and rule checking process. It contains some basic type declarations

with GNAT.OS_Lib;          use GNAT.OS_Lib;

with Asis;                 use Asis;

with ASIS_UL.Source_Table; use ASIS_UL.Source_Table;
with ASIS_UL.Strings;      use ASIS_UL.Strings;

with Gnatcheck.Global_State;

package Gnatcheck.Rules is

   type Rule_Checking_States is (Initial_State, All_Rules_Off);
   --  ???
   --  Used as a state type for traversing???

   subtype Diagnosis_Variant is Natural;
   --  Used to numerate the variants of diagnostic message for the same rule.
   --  Zero means that the rule has exactly one variant of the diagnostic
   --  message

   type Rule_Traversal_State is record
      Rule_Checking_State : Rule_Checking_States;
      --  This field is not used at the moment. In some perspective we may
      --  use it for some fine tuning of rule checking process.

      Detected : Boolean;
      --  Set OFF before calling any rule-specific Pre- or Post-operation. On
      --  return from this call, indicates whether or not the violation of
      --  the corresponding rule is detected

      SF : SF_Id;
      --  The Id of the source currently being processed.

      Diagnosis : Diagnosis_Variant;
      --  For some rules we may have more then one variant of the diagnostic
      --  message. In this case this field should be set to the number of the
      --  variant corresponding to the detected violation.

      Diag_Params : String_Loc;
      --  For some rules the diagnostic message may require parametrization.
      --  If so, this field contains the reference to the string with actual
      --  parameter(s)

      Level_Of_Nonexecutable_Construct : Natural := 0;
      --  Nonexecutable construct is any construct that does not result in any
      --  actions during the program execution. For example, a generic template
      --  and a type definition are nonexecutable constructs, and if they
      --  contain a subprogram call, this call can never be issued from their
      --  code, it can be issued only from the instantiation of this generic or
      --  from the declaration of an object of this type if the default
      --  expression defined in the type definition is really evaluated.

      Line   : Natural := 0;
      Column : Natural := 0;
      --  If these fields are not equal to 0, then they should be used as the
      --  source location for the corresponding diagnostic message. Otherwise
      --  the diagnostic message gets the source location from the Element is
      --  is being denerated for.

   end record;

   procedure Increase_Nonexec_Level (State : in out Rule_Traversal_State);
   procedure Decrease_Nonexec_Level (State : in out Rule_Traversal_State);
   --  Non-executable constructs may be enclosed one in another. So during the
   --  traversal process we have to count the nesting level of such constructs
   --  to have the possibility to detect if we are in executable or in
   --  non-executable context. Increase_Nonexec_Level should be called by the
   --  traversal pre-operation when we enter a non-executable construct,
   --  and Decrease_Nonexec_Level should be called in the Post-operation for
   --  this construct

   function In_Executable_Code
     (State : Rule_Traversal_State)
      return  Boolean;
   --  Tells the caller if we are in the executable context at the given stage
   --  of traversal

   subtype Rule_Name      is String_Access;
   subtype Rule_Help      is String_Access;
   subtype Rule_Diagnosis is String_Access;
   --  Subtypes for storing the string information. What would be better -
   --  string access or using ASIS_UL.Strings utilities???

   -----------------
   -- Rule States --
   -----------------

   --  Each rule may have one of the following states:

   --   Enabled -  the rule should be checked at the moment, this state may
   --              be changed during the gnatcheck run (as a result of passing
   --              a control comment in the analyzed source)

   --   Disabled - the rule is disabled for the given gnatcheck run, this
   --              state cannot be changed during the gnatcheck run

   --   Temporary_Disabled - the rule is disabled at the moment, but it may be
   --              moved into Enabled state lately (as a result of passing
   --              a control comment in the analyzed source)

   --  ??? Something like Disabled_For_This_Source ???
   --  ??? Something like "Disable for all children of given Element", set it
   --      and store the Element in Pre_Op, and turn off in Post op?
   --  ??? Something like "Disable till the end of this source"

   type Rule_States is
     (Enabled,
      Disabled,
      Temporary_Disabled);
   --  ???

   type Rule_Template is tagged record
      Name : Rule_Name;
      --  The only means of rule identification outside gnatcheck. All the
      --  rules implemented in gnatcheck should have unique names, the casing
      --  is not important.

      Synonym : Rule_Name;
      --  Synonym of the rule name. If we have to change the rule name, this
      --  synonym can be used for rule identification

      Rule_State : Rule_States;
      --  Is the rule active or not

      Help_Info : Rule_Help;
      --  Short help information for the rule

      Diagnosis : Rule_Diagnosis;
      --  Message generated in case if a rule violation is detected. A rule may
      --  have more then one diagnostic message associated with it. A
      --  diagnostic message may have formal parameters that should be replaced
      --  with some actual information computed from a specific rule violation.
      --  See the documanttaion of Gnatcheck.Rules.Output.Report_Detection for
      --  more details about diagnosis parametrization and providing more then
      --  one diagnostic message for a rule.

   end record;

   type Rule_Access is access all Rule_Template'Class;

   --------------------------------------------------------
   -- Operations that may be redefined by specific rules --
   --------------------------------------------------------

   procedure Rule_Check_Pre_Op
     (Rule    : in out Rule_Template;
      Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Rule_Traversal_State);

   procedure Rule_Check_Post_Op
     (Rule    : in out Rule_Template;
      Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Rule_Traversal_State);
   --  These two procedures are called for each ASIS Element as a part of the
   --  general ASIS traversal. They perform all the possible local checks.
   --
   --  The template Rule_Check_Pre_Op and Rule_Check_Post_Op do nothing.
   --
   --  Note that the State parameter is used as the means to pass information
   --  (including the number or the diagnostic variant and the reference to
   --  diagnosis actual parameters, see the spec of Gnatcheck.Rules.Output)
   --  to the Gnatcheck.Rules.Output.Report_Detection routine that stores the
   --  diagnoses in the diagnosis database.
   --
   --  See the body of Gnatcheck.Rules.Traversing routines All_Rules_Pre_Op and
   --  All_Rules_Post_Op for more details.

   procedure Init_Rule (Rule : in out Rule_Template);
   --  This is the means to provide the basic rule characteristics, such
   --  as rule name, texts of diagnostic and help messages, rule status etc.

   procedure Process_Rule_Parameter
     (Rule    : in out Rule_Template;
      Param   :        String;
      Enable  :        Boolean);
   --  Is supposed to process a single rule parameter of the gnatcheck call.
   --
   --  If the rule parameter string consists of more then one parameter
   --  separated by ',', then this procedure is called for each Param
   --  substring of the rule parameter that corresponds to the parts separated
   --  by commas. As the substring of the rule parameter, the Param string
   --  satisfies the following conditions:
   --
   --  * it starts from the firts non-blank character after ',' or from the
   --    beginning of the rule parameter;
   --
   --  * it ends with the character immediatelly preceding the next ',';
   --
   --  * it contains at least one non-blank character;
   --
   --  * it does not contain a comma character;
   --
   --  The order of calling these routine for substrings of the rule parameter
   --  string corresponds to the order of this substrings in the rule parameter
   --  string. If the rule parameter string does not contain a comma character,
   --  this procedure is called only once for the whole rule parameter string
   --  without leading blank characters (if any).
   --
   --  See the body of Gnatcheck.Rules.Rule_Table.Process_Rule_Option for
   --  more details of parsing the rule parameter string.
   --
   --  Enable says if the given rule for the given paramener value
   --  should be set ON or OFF (the exact meaning of parameters and
   --  combinations of parameters values with Enable parameter should be
   --  defined individually for each rule). If the Param value (with the
   --  combination of Enable value) is not allowed for a given rule, this
   --  procedure should generate an error message (saying that the given
   --  parameter is ignored for a given rule) and does not do anything
   --  else.
   --
   --  The template generates the error message saying that no parameter can be
   --  set for a given rule and that the parameter is ignored.

   procedure Print_Rule_Help (Rule : Rule_Template);
   --  Prints into Stderr the rule help information

   ------------------
   -- Global rules --
   ------------------

   type Global_Rule_Template is new Rule_Template with null record;
   --  The top of the global rules hierarchy. Adds the following operations:
   --  ???

   procedure Collect_Global_Info_Pre_Op
     (Rule    : in out Global_Rule_Template;
      Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Rule_Traversal_State);

   procedure Collect_Global_Info_Post_Op
     (Rule    : in out Global_Rule_Template;
      Element :        Asis.Element;
      Control : in out Traverse_Control;
      State   : in out Rule_Traversal_State);
   --  These two procedures are called for each ASIS Element as a part of the
   --  general ASIS traversal (for both argument and needed sources). They
   --  compute and store in the global state data structure all the
   --  rule-specific global information. They do not perform any checks.
   --
   --  The template Collect_Global_Info_Pre_Op and Collect_Global_Info_Post_Op
   --  do nothing.

   procedure Init_Global_Structure (Rule : Global_Rule_Template);
   --  This procedure initializes the global structure needed for checking the
   --  rule if this rule is a global rule. ???
   --  The template does nothing.

   procedure Check_Global_Structure_Node
     (Rule     :     Global_Rule_Template;
      N        :     Gnatcheck.Global_State.GS_Node_Id;
      Detected : out Boolean);
   --  For a given rule, checks the given node of the global structure in order
   --  to make the check for this rule. Detected is set ON if the rule
   --  violation is detected for this node and OFF otherwise.
   --  The template does nothing.

   procedure Analyze_Global_Structure (Rule : Global_Rule_Template);
   --  For a given rule, analyzes, changes and checks the integrated state of
   --  the global structure in order to make the check for this rule. This
   --  happens after making the transitive clousure of all the calls.
   --  The template does nothing.
   --  ???

   ----------------------------
   -- Common rule operations --
   ----------------------------

   procedure Register_Rule (Rule : Rule_Access);
   --  Initializes its parameter (by calling Init_Rule for it) and creates
   --  the corresponding element in the rule table for this rule. Ensures that
   --  all the rules have unique names (casing is not important)

end Gnatcheck.Rules;
