From 744220fa4fa92d7f9c9304069cf5fdff5fa52bb4 Mon Sep 17 00:00:00 2001 From: Pierre-Marie de Rodat Date: Mon, 3 Feb 2020 09:06:45 -0500 Subject: [PATCH] Fix handling of null nodes in memoized properties TN: T203-028 --- langkit/templates/properties/def_ada.mako | 22 ++++++++----- .../mmz_on_null/expected_concrete_syntax.lkt | 12 +++++++ .../tests/properties/mmz_on_null/main.adb | 33 +++++++++++++++++++ .../tests/properties/mmz_on_null/test.out | 3 ++ .../tests/properties/mmz_on_null/test.py | 29 ++++++++++++++++ .../tests/properties/mmz_on_null/test.yaml | 1 + 6 files changed, 92 insertions(+), 8 deletions(-) create mode 100644 testsuite/tests/properties/mmz_on_null/expected_concrete_syntax.lkt create mode 100644 testsuite/tests/properties/mmz_on_null/main.adb create mode 100644 testsuite/tests/properties/mmz_on_null/test.out create mode 100644 testsuite/tests/properties/mmz_on_null/test.py create mode 100644 testsuite/tests/properties/mmz_on_null/test.yaml diff --git a/langkit/templates/properties/def_ada.mako b/langkit/templates/properties/def_ada.mako index 6a4e4278b..9a17c77d6 100644 --- a/langkit/templates/properties/def_ada.mako +++ b/langkit/templates/properties/def_ada.mako @@ -143,7 +143,7 @@ begin ## If this property uses env, we want to make sure lexical env caches are up ## to date. % if property.uses_envs: - if Node /= null then + if Self /= null then Reset_Caches (Self.Unit); ## And if it is also public, we need to ensure that lexical @@ -155,6 +155,10 @@ begin % endif % if memoized: + if Self = null then + raise Property_Error with "property called on null node"; + end if; + ## If memoization is enabled for this property, look for an already ## computed result for this property. See the declaration of ## Analysis_Context_Type.In_Populate_Lexical_Env for the rationale about @@ -295,16 +299,18 @@ exception % endif % if memoized: - % if not property.memoize_in_populate: - if not Self.Unit.Context.In_Populate_Lexical_Env then - % endif + if Self /= null then + % if not property.memoize_in_populate: + if not Self.Unit.Context.In_Populate_Lexical_Env then + % endif - Add_Memoized_Value - (Self.Unit, Mmz_Handle, (Kind => Mmz_Property_Error)); + Add_Memoized_Value + (Self.Unit, Mmz_Handle, (Kind => Mmz_Property_Error)); - % if not property.memoize_in_populate: + % if not property.memoize_in_populate: + end if; + % endif end if; - % endif % endif % if has_logging: diff --git a/testsuite/tests/properties/mmz_on_null/expected_concrete_syntax.lkt b/testsuite/tests/properties/mmz_on_null/expected_concrete_syntax.lkt new file mode 100644 index 000000000..332bdcf1c --- /dev/null +++ b/testsuite/tests/properties/mmz_on_null/expected_concrete_syntax.lkt @@ -0,0 +1,12 @@ +grammar None_grammar { + main_rule <- Example(@Example) + +} + +class FooNode { + + @export memoized fun prop (): Boolean = true +} + +class Example : FooNode { +} diff --git a/testsuite/tests/properties/mmz_on_null/main.adb b/testsuite/tests/properties/mmz_on_null/main.adb new file mode 100644 index 000000000..a690a8c57 --- /dev/null +++ b/testsuite/tests/properties/mmz_on_null/main.adb @@ -0,0 +1,33 @@ +with Ada.Exceptions; use Ada.Exceptions; +with Ada.Text_IO; use Ada.Text_IO; + +with Langkit_Support.Diagnostics; use Langkit_Support.Diagnostics; + +with Libfoolang.Analysis; use Libfoolang.Analysis; +with Libfoolang.Common; use Libfoolang.Common; + +procedure Main is + Ctx : constant Analysis_Context := Create_Context; + Unit : constant Analysis_Unit := + Get_From_Buffer (Ctx, "foo.txt", Buffer => "example"); +begin + if Has_Diagnostics (Unit) then + for D of Diagnostics (Unit) loop + Put_Line (To_Pretty_String (D)); + end loop; + raise Program_Error; + end if; + + declare + Dummy : Boolean; + begin + Dummy := Unit.Root.P_Prop; + Put_Line ("No exception..."); + exception + when Exc : Property_Error => + Put_Line ("Got an exception!"); + Put_Line (Exception_Name (Exc) & ": " & Exception_Message (Exc)); + end; + + Put_Line ("main.adb: Done"); +end Main; diff --git a/testsuite/tests/properties/mmz_on_null/test.out b/testsuite/tests/properties/mmz_on_null/test.out new file mode 100644 index 000000000..e08130f9b --- /dev/null +++ b/testsuite/tests/properties/mmz_on_null/test.out @@ -0,0 +1,3 @@ +No exception... +main.adb: Done +Done diff --git a/testsuite/tests/properties/mmz_on_null/test.py b/testsuite/tests/properties/mmz_on_null/test.py new file mode 100644 index 000000000..db572a846 --- /dev/null +++ b/testsuite/tests/properties/mmz_on_null/test.py @@ -0,0 +1,29 @@ +""" +Test that calling a memoized property on a null node triggers the expected +error. +""" + +from __future__ import absolute_import, division, print_function + +from langkit.dsl import ASTNode +from langkit.expressions import langkit_property +from langkit.parsers import Grammar + +from utils import build_and_run + + +class FooNode(ASTNode): + + @langkit_property(public=True, memoized=True) + def prop(): + return True + + +class Example(FooNode): + pass + + +g = Grammar('main_rule') +g.add_rules(main_rule=Example('example')) +build_and_run(g, ada_main='main.adb') +print('Done') diff --git a/testsuite/tests/properties/mmz_on_null/test.yaml b/testsuite/tests/properties/mmz_on_null/test.yaml new file mode 100644 index 000000000..30423a038 --- /dev/null +++ b/testsuite/tests/properties/mmz_on_null/test.yaml @@ -0,0 +1 @@ +driver: python