From 1fd24d2d5e7da11fc9a5234b904255705c87bd60 Mon Sep 17 00:00:00 2001 From: Ben Corby Date: Tue, 17 Dec 2024 13:05:41 +1100 Subject: [PATCH] Add a feature fixed warning message --- mesonbuild/interpreter/interpreter.py | 7 +++- mesonbuild/interpreterbase/__init__.py | 4 +++ mesonbuild/interpreterbase/decorators.py | 46 ++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 1 deletion(-) diff --git a/mesonbuild/interpreter/interpreter.py b/mesonbuild/interpreter/interpreter.py index 59a8ef6a2cbd..5a41a5a2a521 100644 --- a/mesonbuild/interpreter/interpreter.py +++ b/mesonbuild/interpreter/interpreter.py @@ -29,7 +29,7 @@ from ..interpreterbase import noPosargs, noKwargs, permittedKwargs, noArgsFlattening, noSecondLevelHolderResolving, unholder_return from ..interpreterbase import InterpreterException, InvalidArguments, InvalidCode, SubdirDoneRequest from ..interpreterbase import Disabler, disablerIfNotFound -from ..interpreterbase import FeatureNew, FeatureDeprecated, FeatureBroken, FeatureNewKwargs +from ..interpreterbase import FeatureNew, FeatureFixed, FeatureDeprecated, FeatureBroken, FeatureNewKwargs from ..interpreterbase import ObjectHolder, ContextManagerObject from ..interpreterbase import stringifyUserArguments from ..modules import ExtensionModule, ModuleObject, MutableModuleObject, NewExtensionModule, NotFoundExtensionModule @@ -1084,6 +1084,7 @@ def get_option_internal(self, optname: str) -> options.UserOption: @noKwargs def func_get_option(self, nodes: mparser.BaseNode, args: T.Tuple[str], kwargs: 'TYPE_kwargs') -> T.Union[options.UserOption, 'TYPE_var']: + self.get_option_used = True optname = args[0] if ':' in optname: raise InterpreterException('Having a colon in option name is forbidden, ' @@ -1209,6 +1210,10 @@ def func_project(self, node: mparser.FunctionNode, args: T.Tuple[str, T.List[str else: FeatureNew.single_use('meson.options file', '1.1', self.subproject, 'Use meson_options.txt instead') + # Warn about using get_option() in project(). + if hasattr(self, 'get_option_used'): + FeatureFixed.single_use('Using get_option() function as a parameter to project()', '1.7', self.subproject) + if self.subproject: self.project_default_options = {k.evolve(subproject=self.subproject): v for k, v in kwargs['default_options'].items()} diff --git a/mesonbuild/interpreterbase/__init__.py b/mesonbuild/interpreterbase/__init__.py index aa38e949063b..085e8d9ca877 100644 --- a/mesonbuild/interpreterbase/__init__.py +++ b/mesonbuild/interpreterbase/__init__.py @@ -40,9 +40,11 @@ 'typed_kwargs', 'FeatureCheckBase', 'FeatureNew', + 'FeatureFixed', 'FeatureDeprecated', 'FeatureBroken', 'FeatureNewKwargs', + 'FeatureFixedKwargs', 'FeatureDeprecatedKwargs', 'InterpreterBase', @@ -98,9 +100,11 @@ typed_kwargs, FeatureCheckBase, FeatureNew, + FeatureFixed, FeatureDeprecated, FeatureBroken, FeatureNewKwargs, + FeatureFixedKwargs, FeatureDeprecatedKwargs, ) diff --git a/mesonbuild/interpreterbase/decorators.py b/mesonbuild/interpreterbase/decorators.py index 06cac526db22..6751e3da70a1 100644 --- a/mesonbuild/interpreterbase/decorators.py +++ b/mesonbuild/interpreterbase/decorators.py @@ -700,6 +700,49 @@ def log_usage_warning(self, tv: T.Union[str, mesonlib.NoProjectVersion], locatio args.append(self.extra_message) mlog.warning(*args, location=location) +class FeatureFixed(FeatureCheckBase): + """Checks for fixed features""" + + # Class variable, shared across all instances + # + # Format: {subproject: {feature_version: set(feature_names)}} + feature_registry = {} + + @staticmethod + def check_version(target_version: T.Union[str, mesonlib.NoProjectVersion], feature_version: str) -> bool: + if isinstance(target_version, str): + return mesonlib.version_compare_condition_with_min(target_version, feature_version) + else: + # Warn for anything newer than the current semver base slot. + major = coredata.version.split('.', maxsplit=1)[0] + return mesonlib.version_compare(feature_version, f'<{major}.0') + + @staticmethod + def get_warning_str_prefix(tv: T.Union[str, mesonlib.NoProjectVersion]) -> str: + if isinstance(tv, str): + return f'Project specifies a minimum meson_version \'{tv}\' but uses features which were fixed in newer versions:' + else: + return 'Project specifies no minimum version but uses features which were fixed in versions:' + + @staticmethod + def get_notice_str_prefix(tv: T.Union[str, mesonlib.NoProjectVersion]) -> str: + return '' + + def log_usage_warning(self, tv: T.Union[str, mesonlib.NoProjectVersion], location: T.Optional['mparser.BaseNode']) -> None: + if isinstance(tv, str): + prefix = f'Project targets {tv!r}' + else: + prefix = 'Project does not target a minimum version' + args = [ + prefix, + 'but uses a feature fixed in', + f"'{self.feature_version}':", + f'{self.feature_name}.', + ] + if self.extra_message: + args.append(self.extra_message) + mlog.warning(*args, location=location) + class FeatureDeprecated(FeatureCheckBase): """Checks for deprecated features""" @@ -809,5 +852,8 @@ def wrapped(*wrapped_args: T.Any, **wrapped_kwargs: T.Any) -> T.Any: class FeatureNewKwargs(FeatureCheckKwargsBase): feature_check_class = FeatureNew +class FeatureFixedKwargs(FeatureCheckKwargsBase): + feature_check_class = FeatureFixed + class FeatureDeprecatedKwargs(FeatureCheckKwargsBase): feature_check_class = FeatureDeprecated