summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mesonbuild/ast/interpreter.py30
-rw-r--r--mesonbuild/interpreterbase/__init__.py2
-rw-r--r--mesonbuild/interpreterbase/baseobjects.py4
-rw-r--r--test cases/rewrite/7 tricky dataflow/addSrc.json5
-rw-r--r--test cases/rewrite/7 tricky dataflow/info.json5
-rw-r--r--test cases/rewrite/7 tricky dataflow/meson.build6
-rw-r--r--test cases/unit/120 rewrite/meson.build6
-rw-r--r--unittests/rewritetests.py1
8 files changed, 49 insertions, 10 deletions
diff --git a/mesonbuild/ast/interpreter.py b/mesonbuild/ast/interpreter.py
index 473ad9119..62c4839a7 100644
--- a/mesonbuild/ast/interpreter.py
+++ b/mesonbuild/ast/interpreter.py
@@ -13,7 +13,7 @@ from dataclasses import dataclass
import itertools
from pathlib import Path
-from .. import mparser, mesonlib
+from .. import mparser, mesonlib, mlog
from .. import environment
from ..interpreterbase import (
@@ -26,6 +26,7 @@ from ..interpreterbase import (
default_resolve_key,
is_disabled,
UnknownValue,
+ UndefinedVariable,
InterpreterObject,
)
@@ -460,14 +461,14 @@ class AstInterpreter(InterpreterBase):
self.nesting.pop()
for var_name in self.cur_assignments:
potential_values = []
- oldval = self.get_cur_value(var_name, allow_none=True)
- if oldval is not None:
+ oldval = self.get_cur_value_if_defined(var_name)
+ if not isinstance(oldval, UndefinedVariable):
potential_values.append(oldval)
for nesting, value in self.cur_assignments[var_name]:
if len(nesting) > len(self.nesting):
potential_values.append(value)
self.cur_assignments[var_name] = [(nesting, v) for (nesting, v) in self.cur_assignments[var_name] if len(nesting) <= len(self.nesting)]
- if len(potential_values) > 1 or (len(potential_values) > 0 and oldval is None):
+ if len(potential_values) > 1 or (len(potential_values) > 0 and isinstance(oldval, UndefinedVariable)):
uv = UnknownValue()
for pv in potential_values:
self.dataflow_dag.add_edge(pv, uv)
@@ -484,19 +485,28 @@ class AstInterpreter(InterpreterBase):
raise TypeError
return ret
- def get_cur_value(self, var_name: str, allow_none: bool = False) -> T.Union[BaseNode, UnknownValue, None]:
+ def get_cur_value_if_defined(self, var_name: str) -> T.Union[BaseNode, UnknownValue, UndefinedVariable]:
if var_name in {'meson', 'host_machine', 'build_machine', 'target_machine'}:
return UnknownValue()
- ret = None
+ ret: T.Union[BaseNode, UnknownValue, UndefinedVariable] = UndefinedVariable()
for nesting, value in reversed(self.cur_assignments[var_name]):
if len(self.nesting) >= len(nesting) and self.nesting[:len(nesting)] == nesting:
ret = value
break
- if ret is None and allow_none:
- return ret
- if ret is None and self.tainted:
+ if isinstance(ret, UndefinedVariable) and self.tainted:
+ return UnknownValue()
+ return ret
+
+ def get_cur_value(self, var_name: str) -> T.Union[BaseNode, UnknownValue]:
+ ret = self.get_cur_value_if_defined(var_name)
+ if isinstance(ret, UndefinedVariable):
+ path = mlog.get_relative_path(Path(self.current_node.filename), Path(os.getcwd()))
+ mlog.warning(f"{path}:{self.current_node.lineno}:{self.current_node.colno} will always crash if executed, since a variable named `{var_name}` is not defined")
+ # We could add more advanced analysis of code referencing undefined
+ # variables, but it is probably not worth the effort and the
+ # complexity. So we do the simplest thing, returning an
+ # UnknownValue.
return UnknownValue()
- assert ret is not None
return ret
# The function `node_to_runtime_value` takes a node of the ast as an
diff --git a/mesonbuild/interpreterbase/__init__.py b/mesonbuild/interpreterbase/__init__.py
index 473379307..88fa706b9 100644
--- a/mesonbuild/interpreterbase/__init__.py
+++ b/mesonbuild/interpreterbase/__init__.py
@@ -61,6 +61,7 @@ __all__ = [
'HoldableTypes',
'UnknownValue',
+ 'UndefinedVariable',
]
from .baseobjects import (
@@ -85,6 +86,7 @@ from .baseobjects import (
HoldableTypes,
UnknownValue,
+ UndefinedVariable,
)
from .decorators import (
diff --git a/mesonbuild/interpreterbase/baseobjects.py b/mesonbuild/interpreterbase/baseobjects.py
index 7cda5729f..5ad6f4351 100644
--- a/mesonbuild/interpreterbase/baseobjects.py
+++ b/mesonbuild/interpreterbase/baseobjects.py
@@ -127,6 +127,10 @@ class UnknownValue(MesonInterpreterObject):
limitations in our code or because the value differs from machine to
machine.'''
+class UndefinedVariable(MesonInterpreterObject):
+ '''This class is only used for the rewriter/static introspection tool and
+ represents the `value` a meson-variable has if it was never written to.'''
+
HoldableTypes = (HoldableObject, int, bool, str, list, dict)
TYPE_HoldableTypes = T.Union[TYPE_var, HoldableObject]
InterpreterObjectTypeVar = T.TypeVar('InterpreterObjectTypeVar', bound=TYPE_HoldableTypes)
diff --git a/test cases/rewrite/7 tricky dataflow/addSrc.json b/test cases/rewrite/7 tricky dataflow/addSrc.json
index 1b6aa485b..17e42926f 100644
--- a/test cases/rewrite/7 tricky dataflow/addSrc.json
+++ b/test cases/rewrite/7 tricky dataflow/addSrc.json
@@ -68,5 +68,10 @@
"type": "target",
"target": "tgt6",
"operation": "info"
+ },
+ {
+ "type": "target",
+ "target": "tgt7",
+ "operation": "info"
}
]
diff --git a/test cases/rewrite/7 tricky dataflow/info.json b/test cases/rewrite/7 tricky dataflow/info.json
index 5fc65dd8c..8d4ac553a 100644
--- a/test cases/rewrite/7 tricky dataflow/info.json
+++ b/test cases/rewrite/7 tricky dataflow/info.json
@@ -28,5 +28,10 @@
"type": "target",
"target": "tgt6",
"operation": "info"
+ },
+ {
+ "type": "target",
+ "target": "tgt7",
+ "operation": "info"
}
]
diff --git a/test cases/rewrite/7 tricky dataflow/meson.build b/test cases/rewrite/7 tricky dataflow/meson.build
index 4c183ed97..ab572ea59 100644
--- a/test cases/rewrite/7 tricky dataflow/meson.build
+++ b/test cases/rewrite/7 tricky dataflow/meson.build
@@ -33,3 +33,9 @@ dont_add_here_6 = ['foo.c']
gen = generator(find_program('cp'), output: '@BASENAME@_copy.c', arguments: ['@INPUT@', '@OUTPUT@'])
generated = gen.process(dont_add_here_6)
executable('tgt6', generated)
+
+if false
+ # Should produce a warning, but should not crash
+ var = not_defined_1
+ executable('tgt7', not_defined_2, var)
+endif
diff --git a/test cases/unit/120 rewrite/meson.build b/test cases/unit/120 rewrite/meson.build
index 545bb0fde..654b09d16 100644
--- a/test cases/unit/120 rewrite/meson.build
+++ b/test cases/unit/120 rewrite/meson.build
@@ -190,5 +190,11 @@ if a \
debug('help!')
endif
+if false
+ # Should produce a warning, but should not crash
+ foo = not_defined
+ message(not_defined)
+endif
+
# End of file comment with no linebreak \ No newline at end of file
diff --git a/unittests/rewritetests.py b/unittests/rewritetests.py
index 75405efc8..767c29187 100644
--- a/unittests/rewritetests.py
+++ b/unittests/rewritetests.py
@@ -439,6 +439,7 @@ class RewriterTests(BasePlatformTests):
'tgt4@exe': {'name': 'tgt4', 'sources': ['unknown'], 'extra_files': []},
'tgt5@exe': {'name': 'tgt5', 'sources': ['unknown', 'new.c'], 'extra_files': []},
'tgt6@exe': {'name': 'tgt6', 'sources': ['unknown', 'new.c'], 'extra_files': []},
+ 'tgt7@exe': {'name': 'tgt7', 'sources': ['unknown', 'unknown'], 'extra_files': []},
}
}
self.assertEqualIgnoreOrder(out, expected)