如何使用ASIS找到记录中字符串字段的`' First`和`' Last`表达式

时间:2018-05-29 11:11:00

标签: ada asis

我使用ASIS分析一个大型的Ada项目。我需要做的一件事是在记录变量中找到字符串字段的'First'Last表达式。

如果我的Discrete_Range A_Discrete_Simple_Expression_Range不是Lower_Bound(可以直接使用函数Upper_BoundA_Discrete_Range_Attribute_Reference而是with Ada.Text_IO; procedure Minimal_Example is type R is record F : String (1 .. 5); end record; V : R; subtype S is String (V.F'Range); -- It would have been nice if they didn't do like this. function F return S is ("12345"); begin Ada.Text_IO.Put_Line (F); end Minimal_Example; ),我的问题会发生,而是{{ 1}}。

我分析的源代码示例基本上如下:

--  Standard library packages:
with Ada.Wide_Text_IO;

--  ASIS packages:
with Asis;
with Asis.Ada_Environments;
with Asis.Compilation_Units;
with Asis.Declarations;
with Asis.Definitions;
with Asis.Elements;
with Asis.Expressions;
with Asis.Implementation;
with Asis.Iterator;
with Asis.Statements;
with Asis.Text;

procedure Minimal_Analyzer is

  procedure Pre_Operation (Element : in     Asis.Element;
                           Control : in out Asis.Traverse_Control;
                           State   : in out Boolean) is
    pragma Unreferenced (Control, State);

    use all type Asis.Element_Kinds;
    use all type Asis.Statement_Kinds;
  begin
    if Asis.Elements.Element_Kind (Element) = A_Statement and then
       Asis.Elements.Statement_Kind (Element) = A_Procedure_Call_Statement
    then
      for Parameter_Association of Asis.Statements.Call_Statement_Parameters (Statement  => Element,
                                                                              Normalized => True) loop
        declare
          Actual_Parameter   : Asis.Element;
          Type_Of_Expression : Asis.Element;
          Type_Definition    : Asis.Definition;
          Constraint         : Asis.Constraint;
        begin
          Actual_Parameter   := Asis.Expressions.Actual_Parameter (Parameter_Association);
          Type_Of_Expression := Asis.Expressions.Corresponding_Expression_Type (Actual_Parameter);
          Type_Definition    := Asis.Declarations.Type_Declaration_View (Declaration => Type_Of_Expression);
          Constraint         := Asis.Definitions.Subtype_Constraint (Type_Definition);

          for Index_Range of Asis.Definitions.Discrete_Ranges (Constraint) loop
            declare
              Range_Attribute : Asis.Definition;
              Range_Prefix    : Asis.Element;
            begin
              Range_Attribute := Asis.Definitions.Range_Attribute (Index_Range);
              Range_Prefix    := Asis.Expressions.Prefix (Range_Attribute);

              Ada.Wide_Text_IO.Put_Line (Asis.Elements.Debug_Image (Range_Prefix));
              Ada.Wide_Text_IO.Put_Line (Asis.Text.Element_Image (Range_Prefix));
            end;
          end loop;
        end;
      end loop;
    end if;
  end Pre_Operation;

  procedure Post_Operation (Element : in     Asis.Element;
                            Control : in out Asis.Traverse_Control;
                            State   : in out Boolean) is null;

  procedure Traverse_Declaration is
     new Asis.Iterator.Traverse_Element (State_Information => Boolean,
                                         Pre_Operation     => Pre_Operation,
                                         Post_Operation    => Post_Operation);
  Context : Asis.Context;

begin
  Asis.Implementation.Initialize ("");
  Asis.Ada_Environments.Associate (The_Context => Context,
                                   Name        => "CLPG",
                                   Parameters  => "-CA -FM");
  Asis.Ada_Environments.Open (The_Context => Context);

  Analyze :
  declare
    Complation_Unit_Body             : Asis.Compilation_Unit;
    Complation_Unit_Body_Declaration : Asis.Declaration;
    Process_Control                  : Asis.Traverse_Control := Asis.Continue;
    State                            : Boolean := False;
  begin
    Complation_Unit_Body := Asis.Compilation_Units.Compilation_Unit_Body (Name        => "Minimal_Example",
                                                                          The_Context => Context);
    Complation_Unit_Body_Declaration := Asis.Elements.Unit_Declaration (Compilation_Unit => Complation_Unit_Body);

    Traverse_Declaration (Element => Complation_Unit_Body_Declaration,
                          Control => Process_Control,
                          State   => State);
  end Analyze;

  Asis.Ada_Environments.Close (The_Context => Context);
  Asis.Ada_Environments.Dissociate (The_Context => Context);
  Asis.Implementation.Finalize (Parameters => "");
end Minimal_Analyzer;

以下是我用于执行分析的程序的最小化版本:

with "asis";

project Build is

   for Main use ("minimal_analyzer.adb",
                 "minimal_example.adb");

   for Source_Dirs use (".");
   for Object_Dir  use "obj";
   for Exec_Dir    use "bin";

   package Builder is
      for Default_Switches ("Ada") use ("-m",   --  Do not recompile if only comments have changed
                                        "-s",   --  Recompile if switches change
                                        "-j0"); --  Build concurrently
   end Builder;

   package Compiler is
      for Default_Switches ("Ada") use ("-gnatoU",
                                        "-gnat2012",
                                        "-funwind-tables",
                                        "-fstack-check",
                                        "-gnata");

   end Compiler;

end Build;

项目文件:

gprbuild -j0 -p -P build.gpr

构建命令:

minimal_analyzer

您需要安装ASIS才能构建该工具。如果您从minimal_example.adb所在的目录运行Element Debug_Image: A_SELECTED_COMPONENT located in Minimal_Example (body, Unit_Id = 2, Context_Id = 1) text position : minimal_example.adb:8:40 Nodes: Node : 2332 - N_SELECTED_COMPONENT R_Node : 2332 - N_SELECTED_COMPONENT Node_Field_1 : 0 - N_EMPTY Node_Field_2 : 0 - N_EMPTY Rel_Sloc : 157 obtained from the tree /tmp/minimal_example.adt (Tree_Id = 1) V.F ,则会获得输出:

V.F

...但是如何才能了解Discrete_Simple_Expression_Range的定义,以便我可以提取1 .. 5 @Repository public interface TestRepository extends CrudRepository<com.example.demo.Test, Long> { }

1 个答案:

答案 0 :(得分:4)

我找到了解决方案:

诀窍是知道何时使用ASIS.Expressions.Corresponding_Name_Declaration ...

--  Standard library packages:
with Ada.Wide_Text_IO;

--  ASIS packages:
with ASIS;
with ASIS.Ada_Environments;
with ASIS.Compilation_Units;
with ASIS.Declarations;
with ASIS.Definitions;
with ASIS.Elements;
with ASIS.Expressions;
with ASIS.Implementation;
with ASIS.Iterator;
with ASIS.Statements;
with ASIS.Text;

procedure Minimal_Analyzer is

  procedure Pre_Operation (Element : in     ASIS.Element;
                           Control : in out ASIS.Traverse_Control;
                           State   : in out Boolean) is
    pragma Unreferenced (Control, State);

    use all type ASIS.Element_Kinds;
    use all type ASIS.Statement_Kinds;
  begin
    if ASIS.Elements.Element_Kind (Element) = A_Statement and then
       ASIS.Elements.Statement_Kind (Element) = A_Procedure_Call_Statement
    then
      for Parameter_Association of ASIS.Statements.Call_Statement_Parameters (Statement  => Element,
                                                                              Normalized => True) loop
        declare
          Actual_Parameter   : ASIS.Element;
          Type_Of_Expression : ASIS.Element;
          Type_Definition    : ASIS.Definition;
          Constraint         : ASIS.Constraint;
        begin
          Actual_Parameter   := ASIS.Expressions.Actual_Parameter (Parameter_Association);
          Type_Of_Expression := ASIS.Expressions.Corresponding_Expression_Type (Actual_Parameter);
          Type_Definition    := ASIS.Declarations.Type_Declaration_View (Declaration => Type_Of_Expression);
          Constraint         := ASIS.Definitions.Subtype_Constraint (Type_Definition);

          for Index_Range of ASIS.Definitions.Discrete_Ranges (Constraint) loop
            declare
              Range_Attribute       : ASIS.Definition;
              Range_Prefix          : ASIS.Element;
              Field_Name            : ASIS.Defining_Name;
              Field_Declaration     : ASIS.Element;
              Field_Definition      : ASIS.Definition;
              Field_Type_Definition : ASIS.Definition;
              Constraint            : ASIS.Constraint;
            begin
              Range_Attribute       := ASIS.Definitions.Range_Attribute (Index_Range);
              Range_Prefix          := ASIS.Expressions.Prefix (Range_Attribute);
              Field_Name            := ASIS.Expressions.Selector (Range_Prefix);
              Field_Declaration     := ASIS.Expressions.Corresponding_Name_Declaration (Field_Name);
              Field_Definition      := ASIS.Declarations.Object_Declaration_View (Field_Declaration);
              Field_Type_Definition := ASIS.Definitions.Component_Definition_View (Component_Definition => Field_Definition);
              Constraint            := ASIS.Definitions.Subtype_Constraint (Field_Type_Definition);

              for Index_Range of ASIS.Definitions.Discrete_Ranges (Constraint) loop
                declare
                  First, Last : ASIS.Expression;
                begin
                  First := ASIS.Definitions.Lower_Bound (Index_Range);
                  Last  := ASIS.Definitions.Upper_Bound (Index_Range);

                  Ada.Wide_Text_IO.Put_Line (ASIS.Elements.Debug_Image (First));
                  Ada.Wide_Text_IO.Put_Line (ASIS.Text.Element_Image (First));

                  Ada.Wide_Text_IO.Put_Line (ASIS.Elements.Debug_Image (Last));
                  Ada.Wide_Text_IO.Put_Line (ASIS.Text.Element_Image (Last));
                end;
              end loop;
            end;
          end loop;
        end;
      end loop;
    end if;
  end Pre_Operation;

  procedure Post_Operation (Element : in     ASIS.Element;
                            Control : in out ASIS.Traverse_Control;
                            State   : in out Boolean) is null;

  procedure Traverse_Declaration is
     new ASIS.Iterator.Traverse_Element (State_Information => Boolean,
                                         Pre_Operation     => Pre_Operation,
                                         Post_Operation    => Post_Operation);
  Context : ASIS.Context;

begin
  ASIS.Implementation.Initialize ("");
  ASIS.Ada_Environments.Associate (The_Context => Context,
                                   Name        => "CLPG",
                                   Parameters  => "-CA -FM");
  ASIS.Ada_Environments.Open (The_Context => Context);

  Analyze :
  declare
    Complation_Unit_Body             : ASIS.Compilation_Unit;
    Complation_Unit_Body_Declaration : ASIS.Declaration;
    Process_Control                  : ASIS.Traverse_Control := ASIS.Continue;
    State                            : Boolean := False;
  begin
    Complation_Unit_Body := ASIS.Compilation_Units.Compilation_Unit_Body (Name        => "Minimal_Example",
                                                                          The_Context => Context);
    Complation_Unit_Body_Declaration := ASIS.Elements.Unit_Declaration (Compilation_Unit => Complation_Unit_Body);

    Traverse_Declaration (Element => Complation_Unit_Body_Declaration,
                          Control => Process_Control,
                          State   => State);
  end Analyze;

  ASIS.Ada_Environments.Close (The_Context => Context);
  ASIS.Ada_Environments.Dissociate (The_Context => Context);
  ASIS.Implementation.Finalize (Parameters => "");
end Minimal_Analyzer;