Merge changes I0aee679a,I7fb380a3
* changes: Add systemapi as an APEX synonym for stub maps. Refactor tag handling code in stub generator.
This commit is contained in:
@@ -108,7 +108,14 @@ def parse_args() -> argparse.Namespace:
|
||||
parser.add_argument(
|
||||
'--llndk', action='store_true', help='Use the LLNDK variant.')
|
||||
parser.add_argument(
|
||||
'--apex', action='store_true', help='Use the APEX variant.')
|
||||
'--apex',
|
||||
action='store_true',
|
||||
help='Use the APEX variant. Note: equivalent to --system-api.')
|
||||
parser.add_argument(
|
||||
'--system-api',
|
||||
action='store_true',
|
||||
dest='apex',
|
||||
help='Use the SystemAPI variant. Note: equivalent to --apex.')
|
||||
|
||||
parser.add_argument('--api-map',
|
||||
type=resolved_path,
|
||||
|
@@ -19,9 +19,10 @@ import io
|
||||
import textwrap
|
||||
import unittest
|
||||
|
||||
import ndkstubgen
|
||||
import symbolfile
|
||||
from symbolfile import Arch, Tag
|
||||
from symbolfile import Arch, Tags
|
||||
|
||||
import ndkstubgen
|
||||
|
||||
|
||||
# pylint: disable=missing-docstring
|
||||
@@ -38,22 +39,24 @@ class GeneratorTest(unittest.TestCase):
|
||||
version_file, symbol_list_file,
|
||||
Arch('arm'), 9, False, False)
|
||||
|
||||
version = symbolfile.Version('VERSION_PRIVATE', None, [], [
|
||||
symbolfile.Symbol('foo', []),
|
||||
version = symbolfile.Version('VERSION_PRIVATE', None, Tags(), [
|
||||
symbolfile.Symbol('foo', Tags()),
|
||||
])
|
||||
generator.write_version(version)
|
||||
self.assertEqual('', src_file.getvalue())
|
||||
self.assertEqual('', version_file.getvalue())
|
||||
|
||||
version = symbolfile.Version('VERSION', None, [Tag('x86')], [
|
||||
symbolfile.Symbol('foo', []),
|
||||
version = symbolfile.Version('VERSION', None, Tags.from_strs(['x86']),
|
||||
[
|
||||
symbolfile.Symbol('foo', Tags()),
|
||||
])
|
||||
generator.write_version(version)
|
||||
self.assertEqual('', src_file.getvalue())
|
||||
self.assertEqual('', version_file.getvalue())
|
||||
|
||||
version = symbolfile.Version('VERSION', None, [Tag('introduced=14')], [
|
||||
symbolfile.Symbol('foo', []),
|
||||
version = symbolfile.Version('VERSION', None,
|
||||
Tags.from_strs(['introduced=14']), [
|
||||
symbolfile.Symbol('foo', Tags()),
|
||||
])
|
||||
generator.write_version(version)
|
||||
self.assertEqual('', src_file.getvalue())
|
||||
@@ -69,29 +72,29 @@ class GeneratorTest(unittest.TestCase):
|
||||
version_file, symbol_list_file,
|
||||
Arch('arm'), 9, False, False)
|
||||
|
||||
version = symbolfile.Version('VERSION_1', None, [], [
|
||||
symbolfile.Symbol('foo', [Tag('x86')]),
|
||||
version = symbolfile.Version('VERSION_1', None, Tags(), [
|
||||
symbolfile.Symbol('foo', Tags.from_strs(['x86'])),
|
||||
])
|
||||
generator.write_version(version)
|
||||
self.assertEqual('', src_file.getvalue())
|
||||
self.assertEqual('', version_file.getvalue())
|
||||
|
||||
version = symbolfile.Version('VERSION_1', None, [], [
|
||||
symbolfile.Symbol('foo', [Tag('introduced=14')]),
|
||||
version = symbolfile.Version('VERSION_1', None, Tags(), [
|
||||
symbolfile.Symbol('foo', Tags.from_strs(['introduced=14'])),
|
||||
])
|
||||
generator.write_version(version)
|
||||
self.assertEqual('', src_file.getvalue())
|
||||
self.assertEqual('', version_file.getvalue())
|
||||
|
||||
version = symbolfile.Version('VERSION_1', None, [], [
|
||||
symbolfile.Symbol('foo', [Tag('llndk')]),
|
||||
version = symbolfile.Version('VERSION_1', None, Tags(), [
|
||||
symbolfile.Symbol('foo', Tags.from_strs(['llndk'])),
|
||||
])
|
||||
generator.write_version(version)
|
||||
self.assertEqual('', src_file.getvalue())
|
||||
self.assertEqual('', version_file.getvalue())
|
||||
|
||||
version = symbolfile.Version('VERSION_1', None, [], [
|
||||
symbolfile.Symbol('foo', [Tag('apex')]),
|
||||
version = symbolfile.Version('VERSION_1', None, Tags(), [
|
||||
symbolfile.Symbol('foo', Tags.from_strs(['apex'])),
|
||||
])
|
||||
generator.write_version(version)
|
||||
self.assertEqual('', src_file.getvalue())
|
||||
@@ -106,18 +109,17 @@ class GeneratorTest(unittest.TestCase):
|
||||
Arch('arm'), 9, False, False)
|
||||
|
||||
versions = [
|
||||
symbolfile.Version('VERSION_1', None, [], [
|
||||
symbolfile.Symbol('foo', []),
|
||||
symbolfile.Symbol('bar', [Tag('var')]),
|
||||
symbolfile.Symbol('woodly', [Tag('weak')]),
|
||||
symbolfile.Symbol('doodly',
|
||||
[Tag('weak'), Tag('var')]),
|
||||
symbolfile.Version('VERSION_1', None, Tags(), [
|
||||
symbolfile.Symbol('foo', Tags()),
|
||||
symbolfile.Symbol('bar', Tags.from_strs(['var'])),
|
||||
symbolfile.Symbol('woodly', Tags.from_strs(['weak'])),
|
||||
symbolfile.Symbol('doodly', Tags.from_strs(['weak', 'var'])),
|
||||
]),
|
||||
symbolfile.Version('VERSION_2', 'VERSION_1', [], [
|
||||
symbolfile.Symbol('baz', []),
|
||||
symbolfile.Version('VERSION_2', 'VERSION_1', Tags(), [
|
||||
symbolfile.Symbol('baz', Tags()),
|
||||
]),
|
||||
symbolfile.Version('VERSION_3', 'VERSION_1', [], [
|
||||
symbolfile.Symbol('qux', [Tag('versioned=14')]),
|
||||
symbolfile.Version('VERSION_3', 'VERSION_1', Tags(), [
|
||||
symbolfile.Symbol('qux', Tags.from_strs(['versioned=14'])),
|
||||
]),
|
||||
]
|
||||
|
||||
|
@@ -14,18 +14,22 @@
|
||||
# limitations under the License.
|
||||
#
|
||||
"""Parser for Android's version script information."""
|
||||
from dataclasses import dataclass
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
import logging
|
||||
import re
|
||||
from typing import (
|
||||
Dict,
|
||||
Iterable,
|
||||
Iterator,
|
||||
List,
|
||||
Mapping,
|
||||
NewType,
|
||||
Optional,
|
||||
TextIO,
|
||||
Tuple,
|
||||
Union,
|
||||
)
|
||||
|
||||
|
||||
@@ -51,12 +55,53 @@ def logger() -> logging.Logger:
|
||||
return logging.getLogger(__name__)
|
||||
|
||||
|
||||
@dataclass
|
||||
class Tags:
|
||||
"""Container class for the tags attached to a symbol or version."""
|
||||
|
||||
tags: tuple[Tag, ...] = field(default_factory=tuple)
|
||||
|
||||
@classmethod
|
||||
def from_strs(cls, strs: Iterable[str]) -> Tags:
|
||||
"""Constructs tags from a collection of strings.
|
||||
|
||||
Does not decode API levels.
|
||||
"""
|
||||
return Tags(tuple(Tag(s) for s in strs))
|
||||
|
||||
def __contains__(self, tag: Union[Tag, str]) -> bool:
|
||||
return tag in self.tags
|
||||
|
||||
def __iter__(self) -> Iterator[Tag]:
|
||||
yield from self.tags
|
||||
|
||||
@property
|
||||
def has_mode_tags(self) -> bool:
|
||||
"""Returns True if any mode tags (apex, llndk, etc) are set."""
|
||||
return self.has_apex_tags or self.has_llndk_tags
|
||||
|
||||
@property
|
||||
def has_apex_tags(self) -> bool:
|
||||
"""Returns True if any APEX tags are set."""
|
||||
return 'apex' in self.tags or 'systemapi' in self.tags
|
||||
|
||||
@property
|
||||
def has_llndk_tags(self) -> bool:
|
||||
"""Returns True if any LL-NDK tags are set."""
|
||||
return 'llndk' in self.tags
|
||||
|
||||
@property
|
||||
def has_platform_only_tags(self) -> bool:
|
||||
"""Returns True if any platform-only tags are set."""
|
||||
return 'platform-only' in self.tags
|
||||
|
||||
|
||||
@dataclass
|
||||
class Symbol:
|
||||
"""A symbol definition from a symbol file."""
|
||||
|
||||
name: str
|
||||
tags: List[Tag]
|
||||
tags: Tags
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -65,14 +110,22 @@ class Version:
|
||||
|
||||
name: str
|
||||
base: Optional[str]
|
||||
tags: List[Tag]
|
||||
tags: Tags
|
||||
symbols: List[Symbol]
|
||||
|
||||
@property
|
||||
def is_private(self) -> bool:
|
||||
"""Returns True if this version block is private (platform only)."""
|
||||
return self.name.endswith('_PRIVATE') or self.name.endswith('_PLATFORM')
|
||||
|
||||
def get_tags(line: str) -> List[Tag]:
|
||||
|
||||
def get_tags(line: str, api_map: ApiMap) -> Tags:
|
||||
"""Returns a list of all tags on this line."""
|
||||
_, _, all_tags = line.strip().partition('#')
|
||||
return [Tag(e) for e in re.split(r'\s+', all_tags) if e.strip()]
|
||||
return Tags(tuple(
|
||||
decode_api_level_tag(Tag(e), api_map)
|
||||
for e in re.split(r'\s+', all_tags) if e.strip()
|
||||
))
|
||||
|
||||
|
||||
def is_api_level_tag(tag: Tag) -> bool:
|
||||
@@ -104,24 +157,21 @@ def decode_api_level(api: str, api_map: ApiMap) -> int:
|
||||
return api_map[api]
|
||||
|
||||
|
||||
def decode_api_level_tags(tags: Iterable[Tag], api_map: ApiMap) -> List[Tag]:
|
||||
"""Decodes API level code names in a list of tags.
|
||||
def decode_api_level_tag(tag: Tag, api_map: ApiMap) -> Tag:
|
||||
"""Decodes API level code name in a tag.
|
||||
|
||||
Raises:
|
||||
ParseError: An unknown version name was found in a tag.
|
||||
"""
|
||||
decoded_tags = list(tags)
|
||||
for idx, tag in enumerate(tags):
|
||||
if not is_api_level_tag(tag):
|
||||
continue
|
||||
name, value = split_tag(tag)
|
||||
return tag
|
||||
|
||||
name, value = split_tag(tag)
|
||||
try:
|
||||
decoded = str(decode_api_level(value, api_map))
|
||||
decoded_tags[idx] = Tag('='.join([name, decoded]))
|
||||
except KeyError:
|
||||
raise ParseError(f'Unknown version name in tag: {tag}')
|
||||
return decoded_tags
|
||||
return Tag(f'{name}={decoded}')
|
||||
except KeyError as ex:
|
||||
raise ParseError(f'Unknown version name in tag: {tag}') from ex
|
||||
|
||||
|
||||
def split_tag(tag: Tag) -> Tuple[str, str]:
|
||||
@@ -149,55 +199,52 @@ def get_tag_value(tag: Tag) -> str:
|
||||
return split_tag(tag)[1]
|
||||
|
||||
|
||||
def version_is_private(version: str) -> bool:
|
||||
"""Returns True if the version name should be treated as private."""
|
||||
return version.endswith('_PRIVATE') or version.endswith('_PLATFORM')
|
||||
def _should_omit_tags(tags: Tags, arch: Arch, api: int, llndk: bool,
|
||||
apex: bool) -> bool:
|
||||
"""Returns True if the tagged object should be omitted.
|
||||
|
||||
This defines the rules shared between version tagging and symbol tagging.
|
||||
"""
|
||||
# The apex and llndk tags will only exclude APIs from other modes. If in
|
||||
# APEX or LLNDK mode and neither tag is provided, we fall back to the
|
||||
# default behavior because all NDK symbols are implicitly available to APEX
|
||||
# and LLNDK.
|
||||
if tags.has_mode_tags:
|
||||
if not apex and not llndk:
|
||||
return True
|
||||
if apex and not tags.has_apex_tags:
|
||||
return True
|
||||
if llndk and not tags.has_llndk_tags:
|
||||
return True
|
||||
if not symbol_in_arch(tags, arch):
|
||||
return True
|
||||
if not symbol_in_api(tags, arch, api):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def should_omit_version(version: Version, arch: Arch, api: int, llndk: bool,
|
||||
apex: bool) -> bool:
|
||||
"""Returns True if the version section should be ommitted.
|
||||
"""Returns True if the version section should be omitted.
|
||||
|
||||
We want to omit any sections that do not have any symbols we'll have in the
|
||||
stub library. Sections that contain entirely future symbols or only symbols
|
||||
for certain architectures.
|
||||
"""
|
||||
if version_is_private(version.name):
|
||||
if version.is_private:
|
||||
return True
|
||||
if 'platform-only' in version.tags:
|
||||
if version.tags.has_platform_only_tags:
|
||||
return True
|
||||
|
||||
no_llndk_no_apex = ('llndk' not in version.tags
|
||||
and 'apex' not in version.tags)
|
||||
keep = no_llndk_no_apex or \
|
||||
('llndk' in version.tags and llndk) or \
|
||||
('apex' in version.tags and apex)
|
||||
if not keep:
|
||||
return True
|
||||
if not symbol_in_arch(version.tags, arch):
|
||||
return True
|
||||
if not symbol_in_api(version.tags, arch, api):
|
||||
return True
|
||||
return False
|
||||
return _should_omit_tags(version.tags, arch, api, llndk, apex)
|
||||
|
||||
|
||||
def should_omit_symbol(symbol: Symbol, arch: Arch, api: int, llndk: bool,
|
||||
apex: bool) -> bool:
|
||||
"""Returns True if the symbol should be omitted."""
|
||||
no_llndk_no_apex = 'llndk' not in symbol.tags and 'apex' not in symbol.tags
|
||||
keep = no_llndk_no_apex or \
|
||||
('llndk' in symbol.tags and llndk) or \
|
||||
('apex' in symbol.tags and apex)
|
||||
if not keep:
|
||||
return True
|
||||
if not symbol_in_arch(symbol.tags, arch):
|
||||
return True
|
||||
if not symbol_in_api(symbol.tags, arch, api):
|
||||
return True
|
||||
return False
|
||||
return _should_omit_tags(symbol.tags, arch, api, llndk, apex)
|
||||
|
||||
|
||||
def symbol_in_arch(tags: Iterable[Tag], arch: Arch) -> bool:
|
||||
def symbol_in_arch(tags: Tags, arch: Arch) -> bool:
|
||||
"""Returns true if the symbol is present for the given architecture."""
|
||||
has_arch_tags = False
|
||||
for tag in tags:
|
||||
@@ -325,8 +372,7 @@ class SymbolFileParser:
|
||||
"""Parses a single version section and returns a Version object."""
|
||||
assert self.current_line is not None
|
||||
name = self.current_line.split('{')[0].strip()
|
||||
tags = get_tags(self.current_line)
|
||||
tags = decode_api_level_tags(tags, self.api_map)
|
||||
tags = get_tags(self.current_line, self.api_map)
|
||||
symbols: List[Symbol] = []
|
||||
global_scope = True
|
||||
cpp_symbols = False
|
||||
@@ -373,8 +419,7 @@ class SymbolFileParser:
|
||||
'Wildcard global symbols are not permitted.')
|
||||
# Line is now in the format "<symbol-name>; # tags"
|
||||
name, _, _ = self.current_line.strip().partition(';')
|
||||
tags = get_tags(self.current_line)
|
||||
tags = decode_api_level_tags(tags, self.api_map)
|
||||
tags = get_tags(self.current_line, self.api_map)
|
||||
return Symbol(name, tags)
|
||||
|
||||
def next_line(self) -> str:
|
||||
|
@@ -19,7 +19,7 @@ import textwrap
|
||||
import unittest
|
||||
|
||||
import symbolfile
|
||||
from symbolfile import Arch, Tag
|
||||
from symbolfile import Arch, Tag, Tags, Version
|
||||
|
||||
# pylint: disable=missing-docstring
|
||||
|
||||
@@ -35,12 +35,14 @@ class DecodeApiLevelTest(unittest.TestCase):
|
||||
|
||||
class TagsTest(unittest.TestCase):
|
||||
def test_get_tags_no_tags(self) -> None:
|
||||
self.assertEqual([], symbolfile.get_tags(''))
|
||||
self.assertEqual([], symbolfile.get_tags('foo bar baz'))
|
||||
self.assertEqual(Tags(), symbolfile.get_tags('', {}))
|
||||
self.assertEqual(Tags(), symbolfile.get_tags('foo bar baz', {}))
|
||||
|
||||
def test_get_tags(self) -> None:
|
||||
self.assertEqual(['foo', 'bar'], symbolfile.get_tags('# foo bar'))
|
||||
self.assertEqual(['bar', 'baz'], symbolfile.get_tags('foo # bar baz'))
|
||||
self.assertEqual(Tags.from_strs(['foo', 'bar']),
|
||||
symbolfile.get_tags('# foo bar', {}))
|
||||
self.assertEqual(Tags.from_strs(['bar', 'baz']),
|
||||
symbolfile.get_tags('foo # bar baz', {}))
|
||||
|
||||
def test_split_tag(self) -> None:
|
||||
self.assertTupleEqual(('foo', 'bar'),
|
||||
@@ -77,12 +79,14 @@ class TagsTest(unittest.TestCase):
|
||||
}
|
||||
|
||||
tags = [
|
||||
symbolfile.decode_api_level_tag(t, api_map) for t in (
|
||||
Tag('introduced=9'),
|
||||
Tag('introduced-arm=14'),
|
||||
Tag('versioned=16'),
|
||||
Tag('arm'),
|
||||
Tag('introduced=O'),
|
||||
Tag('introduced=P'),
|
||||
)
|
||||
]
|
||||
expected_tags = [
|
||||
Tag('introduced=9'),
|
||||
@@ -92,33 +96,37 @@ class TagsTest(unittest.TestCase):
|
||||
Tag('introduced=9000'),
|
||||
Tag('introduced=9001'),
|
||||
]
|
||||
self.assertListEqual(
|
||||
expected_tags, symbolfile.decode_api_level_tags(tags, api_map))
|
||||
self.assertListEqual(expected_tags, tags)
|
||||
|
||||
with self.assertRaises(symbolfile.ParseError):
|
||||
symbolfile.decode_api_level_tags([Tag('introduced=O')], {})
|
||||
symbolfile.decode_api_level_tag(Tag('introduced=O'), {})
|
||||
|
||||
|
||||
class PrivateVersionTest(unittest.TestCase):
|
||||
def test_version_is_private(self) -> None:
|
||||
self.assertFalse(symbolfile.version_is_private('foo'))
|
||||
self.assertFalse(symbolfile.version_is_private('PRIVATE'))
|
||||
self.assertFalse(symbolfile.version_is_private('PLATFORM'))
|
||||
self.assertFalse(symbolfile.version_is_private('foo_private'))
|
||||
self.assertFalse(symbolfile.version_is_private('foo_platform'))
|
||||
self.assertFalse(symbolfile.version_is_private('foo_PRIVATE_'))
|
||||
self.assertFalse(symbolfile.version_is_private('foo_PLATFORM_'))
|
||||
def mock_version(name: str) -> Version:
|
||||
return Version(name, base=None, tags=Tags(), symbols=[])
|
||||
|
||||
self.assertTrue(symbolfile.version_is_private('foo_PRIVATE'))
|
||||
self.assertTrue(symbolfile.version_is_private('foo_PLATFORM'))
|
||||
self.assertFalse(mock_version('foo').is_private)
|
||||
self.assertFalse(mock_version('PRIVATE').is_private)
|
||||
self.assertFalse(mock_version('PLATFORM').is_private)
|
||||
self.assertFalse(mock_version('foo_private').is_private)
|
||||
self.assertFalse(mock_version('foo_platform').is_private)
|
||||
self.assertFalse(mock_version('foo_PRIVATE_').is_private)
|
||||
self.assertFalse(mock_version('foo_PLATFORM_').is_private)
|
||||
|
||||
self.assertTrue(mock_version('foo_PRIVATE').is_private)
|
||||
self.assertTrue(mock_version('foo_PLATFORM').is_private)
|
||||
|
||||
|
||||
class SymbolPresenceTest(unittest.TestCase):
|
||||
def test_symbol_in_arch(self) -> None:
|
||||
self.assertTrue(symbolfile.symbol_in_arch([], Arch('arm')))
|
||||
self.assertTrue(symbolfile.symbol_in_arch([Tag('arm')], Arch('arm')))
|
||||
self.assertTrue(symbolfile.symbol_in_arch(Tags(), Arch('arm')))
|
||||
self.assertTrue(
|
||||
symbolfile.symbol_in_arch(Tags.from_strs(['arm']), Arch('arm')))
|
||||
|
||||
self.assertFalse(symbolfile.symbol_in_arch([Tag('x86')], Arch('arm')))
|
||||
self.assertFalse(
|
||||
symbolfile.symbol_in_arch(Tags.from_strs(['x86']), Arch('arm')))
|
||||
|
||||
def test_symbol_in_api(self) -> None:
|
||||
self.assertTrue(symbolfile.symbol_in_api([], Arch('arm'), 9))
|
||||
@@ -197,81 +205,99 @@ class OmitVersionTest(unittest.TestCase):
|
||||
def test_omit_private(self) -> None:
|
||||
self.assertFalse(
|
||||
symbolfile.should_omit_version(
|
||||
symbolfile.Version('foo', None, [], []), Arch('arm'), 9, False,
|
||||
False))
|
||||
symbolfile.Version('foo', None, Tags(), []), Arch('arm'), 9,
|
||||
False, False))
|
||||
|
||||
self.assertTrue(
|
||||
symbolfile.should_omit_version(
|
||||
symbolfile.Version('foo_PRIVATE', None, [], []), Arch('arm'),
|
||||
9, False, False))
|
||||
symbolfile.Version('foo_PRIVATE', None, Tags(), []),
|
||||
Arch('arm'), 9, False, False))
|
||||
self.assertTrue(
|
||||
symbolfile.should_omit_version(
|
||||
symbolfile.Version('foo_PLATFORM', None, [], []), Arch('arm'),
|
||||
9, False, False))
|
||||
symbolfile.Version('foo_PLATFORM', None, Tags(), []),
|
||||
Arch('arm'), 9, False, False))
|
||||
|
||||
self.assertTrue(
|
||||
symbolfile.should_omit_version(
|
||||
symbolfile.Version('foo', None, [Tag('platform-only')], []),
|
||||
symbolfile.Version('foo', None,
|
||||
Tags.from_strs(['platform-only']), []),
|
||||
Arch('arm'), 9, False, False))
|
||||
|
||||
def test_omit_llndk(self) -> None:
|
||||
self.assertTrue(
|
||||
symbolfile.should_omit_version(
|
||||
symbolfile.Version('foo', None, [Tag('llndk')], []),
|
||||
symbolfile.Version('foo', None, Tags.from_strs(['llndk']), []),
|
||||
Arch('arm'), 9, False, False))
|
||||
|
||||
self.assertFalse(
|
||||
symbolfile.should_omit_version(
|
||||
symbolfile.Version('foo', None, [], []), Arch('arm'), 9, True,
|
||||
False))
|
||||
symbolfile.Version('foo', None, Tags(), []), Arch('arm'), 9,
|
||||
True, False))
|
||||
self.assertFalse(
|
||||
symbolfile.should_omit_version(
|
||||
symbolfile.Version('foo', None, [Tag('llndk')], []),
|
||||
symbolfile.Version('foo', None, Tags.from_strs(['llndk']), []),
|
||||
Arch('arm'), 9, True, False))
|
||||
|
||||
def test_omit_apex(self) -> None:
|
||||
self.assertTrue(
|
||||
symbolfile.should_omit_version(
|
||||
symbolfile.Version('foo', None, [Tag('apex')], []),
|
||||
symbolfile.Version('foo', None, Tags.from_strs(['apex']), []),
|
||||
Arch('arm'), 9, False, False))
|
||||
|
||||
self.assertFalse(
|
||||
symbolfile.should_omit_version(
|
||||
symbolfile.Version('foo', None, [], []), Arch('arm'), 9, False,
|
||||
True))
|
||||
symbolfile.Version('foo', None, Tags(), []), Arch('arm'), 9,
|
||||
False, True))
|
||||
self.assertFalse(
|
||||
symbolfile.should_omit_version(
|
||||
symbolfile.Version('foo', None, [Tag('apex')], []),
|
||||
symbolfile.Version('foo', None, Tags.from_strs(['apex']), []),
|
||||
Arch('arm'), 9, False, True))
|
||||
|
||||
def test_omit_systemapi(self) -> None:
|
||||
self.assertTrue(
|
||||
symbolfile.should_omit_version(
|
||||
symbolfile.Version('foo', None, Tags.from_strs(['systemapi']),
|
||||
[]), Arch('arm'), 9, False, False))
|
||||
|
||||
self.assertFalse(
|
||||
symbolfile.should_omit_version(
|
||||
symbolfile.Version('foo', None, Tags(), []), Arch('arm'), 9,
|
||||
False, True))
|
||||
self.assertFalse(
|
||||
symbolfile.should_omit_version(
|
||||
symbolfile.Version('foo', None, Tags.from_strs(['systemapi']),
|
||||
[]), Arch('arm'), 9, False, True))
|
||||
|
||||
def test_omit_arch(self) -> None:
|
||||
self.assertFalse(
|
||||
symbolfile.should_omit_version(
|
||||
symbolfile.Version('foo', None, [], []), Arch('arm'), 9, False,
|
||||
False))
|
||||
symbolfile.Version('foo', None, Tags(), []), Arch('arm'), 9,
|
||||
False, False))
|
||||
self.assertFalse(
|
||||
symbolfile.should_omit_version(
|
||||
symbolfile.Version('foo', None, [Tag('arm')], []), Arch('arm'),
|
||||
9, False, False))
|
||||
|
||||
self.assertTrue(
|
||||
symbolfile.should_omit_version(
|
||||
symbolfile.Version('foo', None, [Tag('x86')], []), Arch('arm'),
|
||||
9, False, False))
|
||||
|
||||
def test_omit_api(self) -> None:
|
||||
self.assertFalse(
|
||||
symbolfile.should_omit_version(
|
||||
symbolfile.Version('foo', None, [], []), Arch('arm'), 9, False,
|
||||
False))
|
||||
self.assertFalse(
|
||||
symbolfile.should_omit_version(
|
||||
symbolfile.Version('foo', None, [Tag('introduced=9')], []),
|
||||
symbolfile.Version('foo', None, Tags.from_strs(['arm']), []),
|
||||
Arch('arm'), 9, False, False))
|
||||
|
||||
self.assertTrue(
|
||||
symbolfile.should_omit_version(
|
||||
symbolfile.Version('foo', None, [Tag('introduced=14')], []),
|
||||
symbolfile.Version('foo', None, Tags.from_strs(['x86']), []),
|
||||
Arch('arm'), 9, False, False))
|
||||
|
||||
def test_omit_api(self) -> None:
|
||||
self.assertFalse(
|
||||
symbolfile.should_omit_version(
|
||||
symbolfile.Version('foo', None, Tags(), []), Arch('arm'), 9,
|
||||
False, False))
|
||||
self.assertFalse(
|
||||
symbolfile.should_omit_version(
|
||||
symbolfile.Version('foo', None,
|
||||
Tags.from_strs(['introduced=9']), []),
|
||||
Arch('arm'), 9, False, False))
|
||||
|
||||
self.assertTrue(
|
||||
symbolfile.should_omit_version(
|
||||
symbolfile.Version('foo', None,
|
||||
Tags.from_strs(['introduced=14']), []),
|
||||
Arch('arm'), 9, False, False))
|
||||
|
||||
|
||||
@@ -279,58 +305,72 @@ class OmitSymbolTest(unittest.TestCase):
|
||||
def test_omit_llndk(self) -> None:
|
||||
self.assertTrue(
|
||||
symbolfile.should_omit_symbol(
|
||||
symbolfile.Symbol('foo', [Tag('llndk')]), Arch('arm'), 9,
|
||||
False, False))
|
||||
symbolfile.Symbol('foo', Tags.from_strs(['llndk'])),
|
||||
Arch('arm'), 9, False, False))
|
||||
|
||||
self.assertFalse(
|
||||
symbolfile.should_omit_symbol(symbolfile.Symbol('foo', []),
|
||||
symbolfile.should_omit_symbol(symbolfile.Symbol('foo', Tags()),
|
||||
Arch('arm'), 9, True, False))
|
||||
self.assertFalse(
|
||||
symbolfile.should_omit_symbol(
|
||||
symbolfile.Symbol('foo', [Tag('llndk')]), Arch('arm'), 9, True,
|
||||
False))
|
||||
symbolfile.Symbol('foo', Tags.from_strs(['llndk'])),
|
||||
Arch('arm'), 9, True, False))
|
||||
|
||||
def test_omit_apex(self) -> None:
|
||||
self.assertTrue(
|
||||
symbolfile.should_omit_symbol(
|
||||
symbolfile.Symbol('foo', [Tag('apex')]), Arch('arm'), 9, False,
|
||||
False))
|
||||
symbolfile.Symbol('foo', Tags.from_strs(['apex'])),
|
||||
Arch('arm'), 9, False, False))
|
||||
|
||||
self.assertFalse(
|
||||
symbolfile.should_omit_symbol(symbolfile.Symbol('foo', []),
|
||||
symbolfile.should_omit_symbol(symbolfile.Symbol('foo', Tags()),
|
||||
Arch('arm'), 9, False, True))
|
||||
self.assertFalse(
|
||||
symbolfile.should_omit_symbol(
|
||||
symbolfile.Symbol('foo', [Tag('apex')]), Arch('arm'), 9, False,
|
||||
True))
|
||||
symbolfile.Symbol('foo', Tags.from_strs(['apex'])),
|
||||
Arch('arm'), 9, False, True))
|
||||
|
||||
def test_omit_systemapi(self) -> None:
|
||||
self.assertTrue(
|
||||
symbolfile.should_omit_symbol(
|
||||
symbolfile.Symbol('foo', Tags.from_strs(['systemapi'])),
|
||||
Arch('arm'), 9, False, False))
|
||||
|
||||
self.assertFalse(
|
||||
symbolfile.should_omit_symbol(symbolfile.Symbol('foo', Tags()),
|
||||
Arch('arm'), 9, False, True))
|
||||
self.assertFalse(
|
||||
symbolfile.should_omit_symbol(
|
||||
symbolfile.Symbol('foo', Tags.from_strs(['systemapi'])),
|
||||
Arch('arm'), 9, False, True))
|
||||
|
||||
def test_omit_arch(self) -> None:
|
||||
self.assertFalse(
|
||||
symbolfile.should_omit_symbol(symbolfile.Symbol('foo', []),
|
||||
symbolfile.should_omit_symbol(symbolfile.Symbol('foo', Tags()),
|
||||
Arch('arm'), 9, False, False))
|
||||
self.assertFalse(
|
||||
symbolfile.should_omit_symbol(
|
||||
symbolfile.Symbol('foo', [Tag('arm')]), Arch('arm'), 9, False,
|
||||
False))
|
||||
symbolfile.Symbol('foo', Tags.from_strs(['arm'])), Arch('arm'),
|
||||
9, False, False))
|
||||
|
||||
self.assertTrue(
|
||||
symbolfile.should_omit_symbol(
|
||||
symbolfile.Symbol('foo', [Tag('x86')]), Arch('arm'), 9, False,
|
||||
False))
|
||||
symbolfile.Symbol('foo', Tags.from_strs(['x86'])), Arch('arm'),
|
||||
9, False, False))
|
||||
|
||||
def test_omit_api(self) -> None:
|
||||
self.assertFalse(
|
||||
symbolfile.should_omit_symbol(symbolfile.Symbol('foo', []),
|
||||
symbolfile.should_omit_symbol(symbolfile.Symbol('foo', Tags()),
|
||||
Arch('arm'), 9, False, False))
|
||||
self.assertFalse(
|
||||
symbolfile.should_omit_symbol(
|
||||
symbolfile.Symbol('foo', [Tag('introduced=9')]), Arch('arm'),
|
||||
9, False, False))
|
||||
symbolfile.Symbol('foo', Tags.from_strs(['introduced=9'])),
|
||||
Arch('arm'), 9, False, False))
|
||||
|
||||
self.assertTrue(
|
||||
symbolfile.should_omit_symbol(
|
||||
symbolfile.Symbol('foo', [Tag('introduced=14')]), Arch('arm'),
|
||||
9, False, False))
|
||||
symbolfile.Symbol('foo', Tags.from_strs(['introduced=14'])),
|
||||
Arch('arm'), 9, False, False))
|
||||
|
||||
|
||||
class SymbolFileParseTest(unittest.TestCase):
|
||||
@@ -376,11 +416,11 @@ class SymbolFileParseTest(unittest.TestCase):
|
||||
version = parser.parse_version()
|
||||
self.assertEqual('VERSION_1', version.name)
|
||||
self.assertIsNone(version.base)
|
||||
self.assertEqual(['foo', 'bar'], version.tags)
|
||||
self.assertEqual(Tags.from_strs(['foo', 'bar']), version.tags)
|
||||
|
||||
expected_symbols = [
|
||||
symbolfile.Symbol('baz', []),
|
||||
symbolfile.Symbol('qux', [Tag('woodly'), Tag('doodly')]),
|
||||
symbolfile.Symbol('baz', Tags()),
|
||||
symbolfile.Symbol('qux', Tags.from_strs(['woodly', 'doodly'])),
|
||||
]
|
||||
self.assertEqual(expected_symbols, version.symbols)
|
||||
|
||||
@@ -388,7 +428,7 @@ class SymbolFileParseTest(unittest.TestCase):
|
||||
version = parser.parse_version()
|
||||
self.assertEqual('VERSION_2', version.name)
|
||||
self.assertEqual('VERSION_1', version.base)
|
||||
self.assertEqual([], version.tags)
|
||||
self.assertEqual(Tags(), version.tags)
|
||||
|
||||
def test_parse_version_eof(self) -> None:
|
||||
input_file = io.StringIO(textwrap.dedent("""\
|
||||
@@ -423,12 +463,12 @@ class SymbolFileParseTest(unittest.TestCase):
|
||||
parser.next_line()
|
||||
symbol = parser.parse_symbol()
|
||||
self.assertEqual('foo', symbol.name)
|
||||
self.assertEqual([], symbol.tags)
|
||||
self.assertEqual(Tags(), symbol.tags)
|
||||
|
||||
parser.next_line()
|
||||
symbol = parser.parse_symbol()
|
||||
self.assertEqual('bar', symbol.name)
|
||||
self.assertEqual(['baz', 'qux'], symbol.tags)
|
||||
self.assertEqual(Tags.from_strs(['baz', 'qux']), symbol.tags)
|
||||
|
||||
def test_wildcard_symbol_global(self) -> None:
|
||||
input_file = io.StringIO(textwrap.dedent("""\
|
||||
@@ -497,13 +537,14 @@ class SymbolFileParseTest(unittest.TestCase):
|
||||
versions = parser.parse()
|
||||
|
||||
expected = [
|
||||
symbolfile.Version('VERSION_1', None, [], [
|
||||
symbolfile.Symbol('foo', []),
|
||||
symbolfile.Symbol('bar', [Tag('baz')]),
|
||||
symbolfile.Version('VERSION_1', None, Tags(), [
|
||||
symbolfile.Symbol('foo', Tags()),
|
||||
symbolfile.Symbol('bar', Tags.from_strs(['baz'])),
|
||||
]),
|
||||
symbolfile.Version('VERSION_2', 'VERSION_1', [Tag('wasd')], [
|
||||
symbolfile.Symbol('woodly', []),
|
||||
symbolfile.Symbol('doodly', [Tag('asdf')]),
|
||||
symbolfile.Version(
|
||||
'VERSION_2', 'VERSION_1', Tags.from_strs(['wasd']), [
|
||||
symbolfile.Symbol('woodly', Tags()),
|
||||
symbolfile.Symbol('doodly', Tags.from_strs(['asdf'])),
|
||||
]),
|
||||
]
|
||||
|
||||
@@ -527,10 +568,10 @@ class SymbolFileParseTest(unittest.TestCase):
|
||||
self.assertIsNone(version.base)
|
||||
|
||||
expected_symbols = [
|
||||
symbolfile.Symbol('foo', []),
|
||||
symbolfile.Symbol('bar', [Tag('llndk')]),
|
||||
symbolfile.Symbol('baz', [Tag('llndk'), Tag('apex')]),
|
||||
symbolfile.Symbol('qux', [Tag('apex')]),
|
||||
symbolfile.Symbol('foo', Tags()),
|
||||
symbolfile.Symbol('bar', Tags.from_strs(['llndk'])),
|
||||
symbolfile.Symbol('baz', Tags.from_strs(['llndk', 'apex'])),
|
||||
symbolfile.Symbol('qux', Tags.from_strs(['apex'])),
|
||||
]
|
||||
self.assertEqual(expected_symbols, version.symbols)
|
||||
|
||||
|
@@ -70,9 +70,11 @@ the same line. The supported tags are:
|
||||
|
||||
### apex
|
||||
|
||||
Indicates that the version or symbol is to be exposed in the APEX stubs rather
|
||||
than the NDK. May be used in combination with `llndk` if the symbol is exposed
|
||||
to both APEX and the LL-NDK.
|
||||
Indicates that the version or symbol is to be exposed by an APEX rather than the
|
||||
NDK. For APIs exposed by the platform *for* APEX, use `systemapi`.
|
||||
|
||||
May be used in combination with `llndk` if the symbol is exposed to both APEX
|
||||
and the LL-NDK.
|
||||
|
||||
### future
|
||||
|
||||
@@ -144,6 +146,12 @@ for use by the NDK, LL-NDK, or APEX (similar to Java's `@SystemAPI`). It is
|
||||
preferable to keep such APIs in an entirely separate library to protect them
|
||||
from access via `dlsym`, but this is not always possible.
|
||||
|
||||
### systemapi
|
||||
|
||||
This is a synonym of the `apex` tag. It should be used to clarify that the API
|
||||
is an API exposed by the system for an APEX, whereas `apex` should be used for
|
||||
APIs exposed by an APEX to the platform or another APEX.
|
||||
|
||||
### var
|
||||
|
||||
Used to define a public global variable. By default all symbols are exposed as
|
||||
|
Reference in New Issue
Block a user