mirah 0.1.0.pre-java → 0.1.1-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +736 -0
- data/README.md +71 -0
- data/Rakefile +227 -73
- data/examples/Fib.class +0 -0
- data/examples/macros/{string-each-char.mirah → string_each_char.mirah} +2 -3
- data/examples/simple_class.mirah +3 -3
- data/examples/{dynamic.mirah → simple_class.mirah~} +7 -12
- data/javalib/mirah-bootstrap.jar +0 -0
- data/javalib/mirah-builtins.jar +0 -0
- data/javalib/mirah-compiler.jar +0 -0
- data/javalib/mirah-parser.jar +0 -0
- data/javalib/mirah-util.jar +0 -0
- data/lib/mirah.rb +8 -1
- data/lib/mirah/ast.rb +1 -1
- data/lib/mirah/ast/scope.rb +16 -0
- data/lib/mirah/commands/base.rb +1 -3
- data/lib/mirah/compiler.rb +17 -3
- data/lib/mirah/errors.rb +10 -10
- data/lib/mirah/generator.rb +21 -9
- data/lib/mirah/jvm/compiler.rb +17 -0
- data/lib/mirah/jvm/compiler/base.rb +24 -5
- data/lib/mirah/jvm/compiler/jvm_bytecode.rb +83 -20
- data/lib/mirah/jvm/method_lookup.rb +43 -22
- data/lib/mirah/jvm/types.rb +1 -2
- data/lib/mirah/jvm/types/array_type.rb +1 -6
- data/lib/mirah/jvm/types/ast_ext.rb +31 -0
- data/lib/mirah/jvm/types/basic_types.rb +1 -2
- data/lib/mirah/jvm/types/boolean.rb +11 -10
- data/lib/mirah/jvm/types/extensions.rb +14 -5
- data/lib/mirah/jvm/types/factory.rb +128 -43
- data/lib/mirah/jvm/types/floats.rb +8 -10
- data/lib/mirah/jvm/types/integers.rb +16 -9
- data/lib/mirah/jvm/types/intrinsics.rb +17 -69
- data/lib/mirah/jvm/types/meta_type.rb +5 -0
- data/lib/mirah/jvm/types/methods.rb +317 -151
- data/lib/mirah/jvm/types/methods.rb~ +973 -0
- data/lib/mirah/jvm/types/number.rb +29 -6
- data/lib/mirah/jvm/types/primitive_type.rb +35 -7
- data/lib/mirah/jvm/types/source_mirror.rb +11 -6
- data/lib/mirah/jvm/types/type.rb +52 -0
- data/lib/mirah/jvm/types/type_definition.rb +8 -2
- data/lib/mirah/transform/ast_ext.rb +9 -31
- data/lib/mirah/transform/transformer.rb +1 -1
- data/lib/mirah/typer.rb +2 -1
- data/lib/mirah/util/argument_processor.rb +10 -14
- data/lib/mirah/util/argument_processor.rb~ +146 -0
- data/lib/mirah/util/compilation_state.rb +15 -9
- data/lib/mirah/util/process_errors.rb +8 -2
- data/lib/mirah/version.rb +2 -2
- data/lib/mirah_task.rb +0 -7
- data/test/core/typer_test.rb +21 -13
- data/test/core/util/argument_processor_test.rb +19 -19
- data/test/core/util/class_loader_test.rb +19 -4
- data/test/core/util/compilation_state_test.rb +38 -0
- data/test/fixtures/org/foo/LowerCaseInnerClass$inner.class +0 -0
- data/test/fixtures/org/foo/LowerCaseInnerClass.class +0 -0
- data/test/fixtures/org/foo/LowerCaseInnerClass.java +7 -0
- data/test/jvm/blocks_test.rb +50 -29
- data/test/jvm/bytecode_test_helper.rb +71 -57
- data/test/jvm/cast_test.rb +162 -0
- data/test/jvm/constructors_test.rb +48 -0
- data/test/jvm/enumerable_test.rb +136 -7
- data/test/jvm/example_test.rb +39 -0
- data/test/jvm/factory_test.rb +6 -0
- data/test/jvm/generics_test.rb +0 -5
- data/test/jvm/import_test.rb +81 -0
- data/test/jvm/interface_test.rb +113 -0
- data/test/jvm/java_typer_test.rb +57 -11
- data/test/jvm/jvm_commands_test.rb +24 -0
- data/test/jvm/jvm_compiler_test.rb +186 -370
- data/test/jvm/macros_test.rb +67 -6
- data/test/jvm/main_method_test.rb +1 -1
- data/test/jvm/mirror_compilation_test_helper.rb +24 -0
- data/test/jvm/new_backend_test_helper.rb +25 -0
- data/test/jvm/rescue_test.rb +153 -18
- data/test/jvm/string_test.rb +41 -0
- data/test/jvm/varargs_test.rb +65 -0
- data/test/mirrors/base_type_test.rb +96 -0
- data/test/mirrors/bytecode_mirror_test.rb +86 -0
- data/test/mirrors/generics_test.rb +776 -0
- data/test/mirrors/member_test.rb +69 -0
- data/test/mirrors/method_lookup_test.rb +574 -0
- data/test/mirrors/mirrors_test.rb +562 -0
- data/test/mirrors/simple_async_mirror_loader_test.rb +110 -0
- data/test/mirrors/simple_mirror_loader_test.rb +104 -0
- data/test/test_helper.rb +2 -1
- metadata +244 -217
- data/README.txt +0 -59
- data/javalib/dynalink-0.2.jar +0 -0
- data/lib/mirah/jvm/typer.rb +0 -177
- data/lib/mirah/jvm/types/dynamic_type.rb +0 -45
- data/lib/mirah/jvm/types/unreachable_type.rb +0 -27
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Copyright (c) 2010 The Mirah project authors. All Rights Reserved.
|
|
2
|
+
# All contributing project authors may be found in the NOTICE file.
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
|
|
16
|
+
require 'test/unit'
|
|
17
|
+
require 'mirah'
|
|
18
|
+
|
|
19
|
+
class MembersTest < Test::Unit::TestCase
|
|
20
|
+
java_import 'org.mirah.jvm.mirrors.Member'
|
|
21
|
+
java_import 'org.mirah.jvm.types.JVMType'
|
|
22
|
+
java_import 'org.mirah.jvm.types.MemberKind'
|
|
23
|
+
|
|
24
|
+
class Visitor
|
|
25
|
+
def method_missing(name, *args)
|
|
26
|
+
@visited = name
|
|
27
|
+
end
|
|
28
|
+
attr_reader :visited
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
class FakeType
|
|
32
|
+
include JVMType
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def create_member(kind)
|
|
36
|
+
@flags = kind.name.hash
|
|
37
|
+
@name = "foo#{kind}"
|
|
38
|
+
@klass = FakeType.new
|
|
39
|
+
@args = [FakeType.new]
|
|
40
|
+
@return_type = FakeType.new
|
|
41
|
+
Member.new(@flags, @klass, @name, @args, @return_type, kind)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def check_fields(member, kind)
|
|
45
|
+
assert_equal(@flags, member.flags)
|
|
46
|
+
assert_equal(@name, member.name)
|
|
47
|
+
assert_equal(@klass, member.declaringClass)
|
|
48
|
+
assert_equal(@args, member.argumentTypes.to_a)
|
|
49
|
+
assert_equal(@return_type, member.returnType)
|
|
50
|
+
assert_equal(kind, member.kind)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def check_visitor(member, kind)
|
|
54
|
+
visitor = Visitor.new
|
|
55
|
+
member.accept(visitor, false)
|
|
56
|
+
assert_match(/^#{visitor.visited}/i, "visit#{kind.name.gsub('_','')}call")
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
MemberKind.constants.each do |name|
|
|
60
|
+
eval(<<-EOF)
|
|
61
|
+
def test_#{name}
|
|
62
|
+
kind = MemberKind.const_get(:#{name})
|
|
63
|
+
member = create_member(kind)
|
|
64
|
+
check_fields(member, kind)
|
|
65
|
+
check_visitor(member, kind)
|
|
66
|
+
end
|
|
67
|
+
EOF
|
|
68
|
+
end
|
|
69
|
+
end
|
|
@@ -0,0 +1,574 @@
|
|
|
1
|
+
# Copyright (c) 2010 The Mirah project authors. All Rights Reserved.
|
|
2
|
+
# All contributing project authors may be found in the NOTICE file.
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
|
|
16
|
+
require 'test/unit'
|
|
17
|
+
require 'mirah'
|
|
18
|
+
|
|
19
|
+
class BaseMethodLookupTest < Test::Unit::TestCase
|
|
20
|
+
java_import 'org.mirah.jvm.mirrors.MirrorTypeSystem'
|
|
21
|
+
java_import 'org.mirah.jvm.mirrors.JVMScope'
|
|
22
|
+
java_import 'org.mirah.jvm.mirrors.BaseType'
|
|
23
|
+
java_import 'org.mirah.jvm.mirrors.MethodLookup'
|
|
24
|
+
java_import 'org.mirah.jvm.mirrors.LookupState'
|
|
25
|
+
java_import 'org.mirah.jvm.mirrors.FakeMember'
|
|
26
|
+
java_import 'org.mirah.jvm.mirrors.Member'
|
|
27
|
+
java_import 'org.mirah.jvm.mirrors.MetaType'
|
|
28
|
+
java_import 'org.mirah.jvm.types.MemberKind'
|
|
29
|
+
java_import 'org.mirah.typer.BaseTypeFuture'
|
|
30
|
+
java_import 'org.mirah.typer.ErrorType'
|
|
31
|
+
java_import 'org.jruby.org.objectweb.asm.Opcodes'
|
|
32
|
+
java_import 'org.jruby.org.objectweb.asm.Type'
|
|
33
|
+
|
|
34
|
+
class FakeMirror < BaseType
|
|
35
|
+
def initialize(desc, superclass=nil, flags=Opcodes.ACC_PUBLIC)
|
|
36
|
+
super(nil, Type.getType(desc), flags, superclass)
|
|
37
|
+
@fields = {}
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def add_field(name, flags=Opcodes.ACC_PUBLIC)
|
|
41
|
+
|
|
42
|
+
kind = if (flags & Opcodes.ACC_STATIC) == 0
|
|
43
|
+
MemberKind::FIELD_ACCESS
|
|
44
|
+
else
|
|
45
|
+
MemberKind::STATIC_FIELD_ACCESS
|
|
46
|
+
end
|
|
47
|
+
@fields[name] = Member.new(flags, self, name, [], self, kind)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def getDeclaredField(name)
|
|
51
|
+
@fields[name]
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def setup
|
|
56
|
+
@types = MirrorTypeSystem.new
|
|
57
|
+
@scope = JVMScope.new
|
|
58
|
+
@lookup = MethodLookup.new(@types.context)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def jvmtype(internal_name, flags=0, superclass=nil)
|
|
62
|
+
BaseType.new(@types.context, Type.getObjectType(internal_name), flags, superclass || wrap('Ljava/lang/Object;'))
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def wrap(descriptor)
|
|
66
|
+
wrap_type(Type.getType(descriptor))
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def wrap_type(type)
|
|
70
|
+
@types.wrap(type).resolve
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def make_method(tag, flags=-1)
|
|
74
|
+
FakeMember.create(@types, tag, flags)
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
class MethodLookupTest < BaseMethodLookupTest
|
|
79
|
+
def test_object_supertype
|
|
80
|
+
main_future = @types.getMainType(nil, nil)
|
|
81
|
+
object = @types.getSuperClass(main_future).resolve
|
|
82
|
+
main = main_future.resolve
|
|
83
|
+
assert(MethodLookup.isSubType(main, main))
|
|
84
|
+
assert(MethodLookup.isSubType(main, object))
|
|
85
|
+
assert_false(MethodLookup.isSubType(object, main))
|
|
86
|
+
error = ErrorType.new([['Error']])
|
|
87
|
+
assert(MethodLookup.isSubType(error, main))
|
|
88
|
+
assert(MethodLookup.isSubType(main, error))
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# TODO interfaces
|
|
92
|
+
def check_supertypes(type, *supertypes)
|
|
93
|
+
supertypes.each do |supertype|
|
|
94
|
+
assert_block("Expected #{type} < #{supertype}") do
|
|
95
|
+
MethodLookup.isSubType(type, supertype)
|
|
96
|
+
end
|
|
97
|
+
assert_block("Expected #{type}.assignableFrom(#{supertype})") do
|
|
98
|
+
supertype.assignableFrom(type)
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def check_not_supertypes(type, *supertypes)
|
|
104
|
+
supertypes.each do |supertype|
|
|
105
|
+
assert_block("Expected !(#{type} < #{supertype})") do
|
|
106
|
+
!MethodLookup.isSubType(type, supertype)
|
|
107
|
+
end
|
|
108
|
+
assert_block("Expected #{type}.assignableFrom(#{supertype}) = false") do
|
|
109
|
+
!supertype.assignableFrom(type)
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def test_primitive_supertypes
|
|
115
|
+
double = wrap('D')
|
|
116
|
+
float = wrap('F')
|
|
117
|
+
long = wrap('J')
|
|
118
|
+
int = wrap('I')
|
|
119
|
+
short = wrap('S')
|
|
120
|
+
char = wrap('C')
|
|
121
|
+
byte = wrap('B')
|
|
122
|
+
bool = wrap('Z')
|
|
123
|
+
check_supertypes(double, double)
|
|
124
|
+
check_not_supertypes(double, float, long, int, short, char, byte, bool)
|
|
125
|
+
check_supertypes(float, double, float)
|
|
126
|
+
check_not_supertypes(float, long, int, short, char, byte, bool)
|
|
127
|
+
check_supertypes(long, double, float, long)
|
|
128
|
+
check_not_supertypes(long, int, short, char, byte, bool)
|
|
129
|
+
check_supertypes(int, double, float, long, int)
|
|
130
|
+
check_not_supertypes(int, short, char, byte, bool)
|
|
131
|
+
check_supertypes(short, double, float, long, int, short)
|
|
132
|
+
check_not_supertypes(short, char, byte, bool)
|
|
133
|
+
check_supertypes(char, double, float, long, int, char)
|
|
134
|
+
check_not_supertypes(char, byte, bool)
|
|
135
|
+
check_supertypes(byte, double, float, long, int, short)
|
|
136
|
+
check_not_supertypes(byte, char, bool)
|
|
137
|
+
check_supertypes(bool, bool)
|
|
138
|
+
check_not_supertypes(bool, double, float, long, int, short, char, byte)
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def array(desc)
|
|
142
|
+
@types.getArrayType(wrap(desc))
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def test_array_supertypes
|
|
146
|
+
check_supertypes(array("I"),
|
|
147
|
+
array("I"),
|
|
148
|
+
wrap("Ljava/lang/Object;"),
|
|
149
|
+
wrap("Ljava/lang/Cloneable;"),
|
|
150
|
+
wrap("Ljava/io/Serializable;"))
|
|
151
|
+
check_not_supertypes(array("I"), array("J"), array("S"), array("D"),
|
|
152
|
+
array("Ljava/lang/Object;"))
|
|
153
|
+
check_supertypes(array("Ljava/util/Map;"),
|
|
154
|
+
wrap("Ljava/lang/Object;"),
|
|
155
|
+
wrap("Ljava/lang/Cloneable;"),
|
|
156
|
+
wrap("Ljava/io/Serializable;"),
|
|
157
|
+
array("Ljava/lang/Object;"),
|
|
158
|
+
array("Ljava/util/Map;"))
|
|
159
|
+
check_supertypes(array("Ljava/util/HashMap;"),
|
|
160
|
+
wrap("Ljava/lang/Object;"),
|
|
161
|
+
wrap("Ljava/lang/Cloneable;"),
|
|
162
|
+
wrap("Ljava/io/Serializable;"),
|
|
163
|
+
array("Ljava/lang/Object;"),
|
|
164
|
+
array("Ljava/util/Map;"),
|
|
165
|
+
array("Ljava/io/Serializable;"),
|
|
166
|
+
array("Ljava/util/AbstractMap;"))
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def test_subtype_comparison
|
|
170
|
+
double = wrap('D')
|
|
171
|
+
int = wrap('I')
|
|
172
|
+
short = wrap('S')
|
|
173
|
+
assert_equal(0.0, MethodLookup.subtypeComparison(double, double))
|
|
174
|
+
assert_equal(0.0, MethodLookup.subtypeComparison(int, int))
|
|
175
|
+
assert_equal(1.0, MethodLookup.subtypeComparison(int, double))
|
|
176
|
+
assert_equal(-1.0, MethodLookup.subtypeComparison(double, int))
|
|
177
|
+
assert_equal(-1.0, MethodLookup.subtypeComparison(int, short))
|
|
178
|
+
assert_equal(1.0, MethodLookup.subtypeComparison(short, int))
|
|
179
|
+
|
|
180
|
+
main = @types.getMainType(nil, nil).resolve
|
|
181
|
+
assert_equal(0.0, MethodLookup.subtypeComparison(main, main))
|
|
182
|
+
assert(MethodLookup.subtypeComparison(double, main).nan?)
|
|
183
|
+
assert(MethodLookup.subtypeComparison(main, int).nan?)
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def test_boxing
|
|
187
|
+
a = @types.getBooleanType.resolve
|
|
188
|
+
b = @types.wrap(Type.getType('Ljava/lang/Boolean;')).resolve
|
|
189
|
+
c = @types.getFixnumType(1).resolve
|
|
190
|
+
assert(!MethodLookup.isSubType(a, b))
|
|
191
|
+
assert(!MethodLookup.isSubType(b, a))
|
|
192
|
+
assert(MethodLookup.isSubTypeWithConversion(a, b))
|
|
193
|
+
assert(MethodLookup.isSubTypeWithConversion(b, a))
|
|
194
|
+
assert(!MethodLookup.isSubTypeWithConversion(c, b))
|
|
195
|
+
assert(!MethodLookup.isSubTypeWithConversion(b, c))
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
def test_pickMostSpecific
|
|
199
|
+
m = MethodLookup.pickMostSpecific([make_method('@I.()V'), make_method('@Z.()V')])
|
|
200
|
+
# Both ambiguous, one should be picked but it doesn't matter which
|
|
201
|
+
assert_kind_of(FakeMember, m)
|
|
202
|
+
|
|
203
|
+
expected = make_method('Z.()V')
|
|
204
|
+
methods = [expected, make_method('@I.()V'), make_method('@S.()V')].shuffle
|
|
205
|
+
assert_same(expected, MethodLookup.pickMostSpecific(methods))
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def test_getPackage
|
|
209
|
+
assert_equal("", MethodLookup.getPackage(jvmtype('Foo')))
|
|
210
|
+
assert_equal("java/lang", MethodLookup.getPackage(wrap('Ljava/lang/String;')))
|
|
211
|
+
assert_equal("java/util", MethodLookup.getPackage(wrap('Ljava/util/Map$Entry;')))
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
def visibility_string(flags)
|
|
215
|
+
if 0 != (flags & Opcodes.ACC_PUBLIC)
|
|
216
|
+
return :public
|
|
217
|
+
elsif 0 != (flags & Opcodes.ACC_PROTECTED)
|
|
218
|
+
return :protected
|
|
219
|
+
elsif 0 != (flags & Opcodes.ACC_PRIVATE)
|
|
220
|
+
return :private
|
|
221
|
+
else
|
|
222
|
+
return :'package private'
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
def assert_visible(type, flags, visible, invisible=[], target=nil)
|
|
227
|
+
visible.each do |t|
|
|
228
|
+
accessibility_assertion(type, flags, t, true, target)
|
|
229
|
+
end
|
|
230
|
+
invisible.each do |t|
|
|
231
|
+
accessibility_assertion(type, flags, t, false, target)
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
def set_self_type(type)
|
|
236
|
+
future = BaseTypeFuture.new
|
|
237
|
+
future.resolved(type)
|
|
238
|
+
@scope.selfType_set(future)
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
def accessibility_assertion(a, flags, b, expected, target=nil)
|
|
242
|
+
assert_block "Expected #{visibility_string(flags)} #{a} #{expected ? '' : ' not '} visible from #{b}" do
|
|
243
|
+
set_self_type(b)
|
|
244
|
+
actual = MethodLookup.isAccessible(a, flags, @scope, target)
|
|
245
|
+
actual == expected
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
def test_isAccessible
|
|
250
|
+
object = wrap('Ljava/lang/Object;')
|
|
251
|
+
string = wrap('Ljava/lang/String;')
|
|
252
|
+
foo = jvmtype('Foo')
|
|
253
|
+
assert_visible(object, Opcodes.ACC_PUBLIC, [object, string, foo])
|
|
254
|
+
assert_visible(object, Opcodes.ACC_PROTECTED, [object, string, foo])
|
|
255
|
+
assert_visible(object, Opcodes.ACC_PRIVATE, [object], [string, foo])
|
|
256
|
+
assert_visible(object, 0, [object, string], [foo])
|
|
257
|
+
assert_visible(foo, Opcodes.ACC_PRIVATE, [foo], [object, string])
|
|
258
|
+
assert_visible(foo, Opcodes.ACC_PROTECTED, [foo], [object, string])
|
|
259
|
+
assert_visible(string, Opcodes.ACC_PROTECTED, [string, object], [foo]) # visible to same package
|
|
260
|
+
assert_visible(string, 0, [string, object], [foo])
|
|
261
|
+
|
|
262
|
+
# instance method from static scope
|
|
263
|
+
assert_visible(object, Opcodes.ACC_PUBLIC, [], [object, foo],
|
|
264
|
+
MetaType.new(object))
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
def assert_methods_visible(methods, type, expected_visible)
|
|
268
|
+
methods_desc = methods.inspect
|
|
269
|
+
expected_invisible = methods - expected_visible
|
|
270
|
+
set_self_type(type)
|
|
271
|
+
invisible = @lookup.removeInaccessible(methods, @scope, nil)
|
|
272
|
+
assert_equal(expected_invisible.map {|m| m.toString}, invisible.map {|m| m.toString})
|
|
273
|
+
assert_equal(expected_visible.map {|m| m.toString}, methods.map {|m| m.toString})
|
|
274
|
+
# TODO: fix protected usage. e.g. Foo can call Object.clone() through a foo instance, but not any Object.
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
def test_removeInaccessible
|
|
278
|
+
# test method from an inaccessible class
|
|
279
|
+
methods = [make_method("Ljava/lang/AbstractStringBuilder;.(I)V"), make_method("Ljava/lang/StringBuilder;.(I)V")]
|
|
280
|
+
assert_methods_visible(methods, wrap('Ljava/util/Map;'), [methods[1]])
|
|
281
|
+
|
|
282
|
+
# test inaccessible method
|
|
283
|
+
methods = [make_method("Ljava/lang/Object;.()V", Opcodes.ACC_PRIVATE), make_method("Ljava/lang/String;.()V")]
|
|
284
|
+
assert_methods_visible(methods, wrap('Ljava/util/Map;'), [methods[1]])
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
def test_gatherMethods
|
|
288
|
+
methods = @lookup.gatherMethods(wrap('Ljava/lang/String;'), 'toString')
|
|
289
|
+
assert_equal(3, methods.size)
|
|
290
|
+
|
|
291
|
+
declaring_classes = Set.new(methods.map {|m| m.declaringClass})
|
|
292
|
+
assert_equal(Set.new([wrap('Ljava/lang/Object;'),
|
|
293
|
+
wrap('Ljava/lang/String;'),
|
|
294
|
+
wrap('Ljava/lang/CharSequence;')]),
|
|
295
|
+
declaring_classes)
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
def test_method_splitting
|
|
299
|
+
set_self_type(jvmtype('Foo'))
|
|
300
|
+
methods = [make_method("Ljava/lang/Object;.()V", Opcodes.ACC_PRIVATE), make_method("Ljava/lang/String;.()V")]
|
|
301
|
+
state = LookupState.new(@types.context, @scope, wrap('Ljava/lang/String;'), methods, nil)
|
|
302
|
+
assert_equal("{potentials: 1 0 inaccessible: 1 0}", state.toString)
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
def test_search
|
|
306
|
+
set_self_type(jvmtype('Foo'))
|
|
307
|
+
methods = [make_method("Ljava/lang/Object;.()V")]
|
|
308
|
+
state = LookupState.new(@types.context, @scope, wrap('Ljava/lang/String;'), methods, nil)
|
|
309
|
+
state.search([], nil)
|
|
310
|
+
assert_equal("{1 methods 0 macros 0 inaccessible}", state.toString)
|
|
311
|
+
future = state.future(false)
|
|
312
|
+
assert_not_nil(future)
|
|
313
|
+
type = future.resolve
|
|
314
|
+
assert(!type.isError)
|
|
315
|
+
assert_equal("Ljava/lang/String;", type.returnType.asm_type.descriptor)
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
def test_findMethod
|
|
319
|
+
set_self_type(jvmtype('Foo'))
|
|
320
|
+
type = @lookup.findMethod(@scope, wrap('Ljava/lang/String;'), 'toString', [], nil, nil, false).resolve
|
|
321
|
+
assert(!type.isError, type.toString)
|
|
322
|
+
assert_nil(@lookup.findMethod(@scope, wrap('Ljava/lang/String;'), 'foobar', [], nil, nil, false))
|
|
323
|
+
type = @lookup.findMethod(@scope, wrap('Ljava/lang/Object;'), 'registerNatives', [], nil, nil, false).resolve
|
|
324
|
+
assert(type.isError)
|
|
325
|
+
assert_equal('Cannot access java.lang.Object.registerNatives() from Foo', type.message[0][0])
|
|
326
|
+
type = @lookup.findMethod(@scope, wrap('Ljava/lang/Object;'), 'clone', [], nil, nil, false).resolve
|
|
327
|
+
assert(type.isError)
|
|
328
|
+
assert_equal('Cannot access java.lang.Object.clone() from Foo', type.message[0][0])
|
|
329
|
+
# TODO test ambiguous
|
|
330
|
+
# TODO check calling instance method from static scope.
|
|
331
|
+
end
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
class CompareSpecificityTest < BaseMethodLookupTest
|
|
335
|
+
def test_same_method
|
|
336
|
+
m = 'I.(I)V'
|
|
337
|
+
assert_specificity_equal(m, m)
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
def assert_more_specific(a, b)
|
|
341
|
+
assert_specificity(a, b, 1.0)
|
|
342
|
+
assert_specificity(b, a, -1.0)
|
|
343
|
+
end
|
|
344
|
+
|
|
345
|
+
def assert_less_specific(a, b)
|
|
346
|
+
assert_more_specific(b, a)
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
def assert_specificity_equal(a, b)
|
|
350
|
+
assert_specificity(a, b, 0.0)
|
|
351
|
+
assert_specificity(b, a, 0.0)
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
def assert_ambiguous(a, b)
|
|
355
|
+
nan = 0.0 / 0.0
|
|
356
|
+
assert_specificity(a, b, nan)
|
|
357
|
+
assert_specificity(b, a, nan)
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
def assert_specificity(a, b, value)
|
|
361
|
+
actual = MethodLookup.compareSpecificity(make_method(a), make_method(b))
|
|
362
|
+
assert_block "Expected compareSpecificity(#{a.inspect}, #{b.inspect}) = #{value} but was #{actual}" do
|
|
363
|
+
if value.nan?
|
|
364
|
+
actual.nan?
|
|
365
|
+
else
|
|
366
|
+
actual == value
|
|
367
|
+
end
|
|
368
|
+
end
|
|
369
|
+
end
|
|
370
|
+
|
|
371
|
+
def test_target
|
|
372
|
+
a = 'I.()V'
|
|
373
|
+
b = 'S.()V'
|
|
374
|
+
|
|
375
|
+
assert_more_specific(b, a)
|
|
376
|
+
end
|
|
377
|
+
|
|
378
|
+
def test_target_with_same_args
|
|
379
|
+
a = 'I.(II)V'
|
|
380
|
+
b = 'S.(II)V'
|
|
381
|
+
|
|
382
|
+
assert_more_specific(b, a)
|
|
383
|
+
end
|
|
384
|
+
|
|
385
|
+
def test_ambiguous_target
|
|
386
|
+
# if the target is ambiguous the result should be equal
|
|
387
|
+
assert_specificity_equal('Z.()V', 'I.()V')
|
|
388
|
+
assert_specificity_equal('Z.(I)V', 'I.(I)V')
|
|
389
|
+
assert_specificity_equal('Z.(II)V', 'I.(II)V')
|
|
390
|
+
|
|
391
|
+
# unless the arguments are different
|
|
392
|
+
assert_ambiguous('Z.(S)V', 'I.(I)V')
|
|
393
|
+
assert_ambiguous('Z.(I)V', 'I.(S)V')
|
|
394
|
+
end
|
|
395
|
+
|
|
396
|
+
def test_arguments
|
|
397
|
+
assert_more_specific('I.(S)V', 'I.(I)V')
|
|
398
|
+
assert_more_specific('I.(SS)V', 'I.(II)V')
|
|
399
|
+
assert_more_specific('I.(SI)V', 'I.(II)V')
|
|
400
|
+
assert_more_specific('I.(IS)V', 'I.(II)V')
|
|
401
|
+
end
|
|
402
|
+
|
|
403
|
+
def test_ambiguous_arguments
|
|
404
|
+
assert_ambiguous('I.(S)V', 'I.(Z)V')
|
|
405
|
+
assert_ambiguous('I.(S)V', 'S.(Z)V')
|
|
406
|
+
assert_ambiguous('S.(S)V', 'I.(Z)V')
|
|
407
|
+
end
|
|
408
|
+
|
|
409
|
+
def test_return_type_ignored
|
|
410
|
+
a = 'I.()I'
|
|
411
|
+
b = 'I.()S'
|
|
412
|
+
c = 'C.()D'
|
|
413
|
+
assert_specificity_equal(a, b)
|
|
414
|
+
assert_more_specific(c, a)
|
|
415
|
+
assert_more_specific(c, b)
|
|
416
|
+
end
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
class FindMaximallySpecificTest < BaseMethodLookupTest
|
|
420
|
+
def find_maximally_specific(method_tags)
|
|
421
|
+
methods = {}
|
|
422
|
+
method_tags.each do |m|
|
|
423
|
+
method = make_method(m)
|
|
424
|
+
methods[method] = m
|
|
425
|
+
end
|
|
426
|
+
result = MethodLookup.findMaximallySpecific(methods.keys)
|
|
427
|
+
result.map {|m| methods[m] || m}
|
|
428
|
+
end
|
|
429
|
+
|
|
430
|
+
def assert_most_specific(expected, methods)
|
|
431
|
+
assert_maximal([expected], methods)
|
|
432
|
+
end
|
|
433
|
+
|
|
434
|
+
def assert_maximal(expected, methods)
|
|
435
|
+
actual = find_maximally_specific(methods)
|
|
436
|
+
assert_equal(Set.new(expected), Set.new(actual))
|
|
437
|
+
end
|
|
438
|
+
|
|
439
|
+
def test_single_method
|
|
440
|
+
m = 'I.()V'
|
|
441
|
+
assert_most_specific(m, [m])
|
|
442
|
+
end
|
|
443
|
+
|
|
444
|
+
def test_more_specific
|
|
445
|
+
a = 'I.(I)V'
|
|
446
|
+
b = 'I.(S)V'
|
|
447
|
+
assert_most_specific(b, [a, b])
|
|
448
|
+
end
|
|
449
|
+
|
|
450
|
+
def test_ambiguous
|
|
451
|
+
a = 'I.(II)V'
|
|
452
|
+
b = 'I.(SI)V'
|
|
453
|
+
c = 'I.(IS)V'
|
|
454
|
+
assert_maximal([b, c], [a, b, c])
|
|
455
|
+
end
|
|
456
|
+
|
|
457
|
+
def test_all_abstract
|
|
458
|
+
a = 'I.(II)V'
|
|
459
|
+
b = '@I.(SI)V'
|
|
460
|
+
c = '@Z.(SI)V'
|
|
461
|
+
result = find_maximally_specific([a, b, c])
|
|
462
|
+
# either b or c should be picked.
|
|
463
|
+
begin
|
|
464
|
+
assert_equal([b], result)
|
|
465
|
+
rescue
|
|
466
|
+
assert_equal([c], result)
|
|
467
|
+
end
|
|
468
|
+
end
|
|
469
|
+
|
|
470
|
+
def test_one_not_abstract
|
|
471
|
+
a = 'I.(SI)V'
|
|
472
|
+
b = '@I.(SI)V'
|
|
473
|
+
c = '@Z.(SI)V'
|
|
474
|
+
assert_most_specific(a, [a, b, c])
|
|
475
|
+
end
|
|
476
|
+
end
|
|
477
|
+
|
|
478
|
+
class Phase1Test < BaseMethodLookupTest
|
|
479
|
+
def phase1(methods, params)
|
|
480
|
+
methods = @lookup.phase1(methods.map{|m| make_method(m)}, params.map{|p| wrap(p)})
|
|
481
|
+
methods.map {|m| m.toString } if methods
|
|
482
|
+
end
|
|
483
|
+
|
|
484
|
+
def test_no_match
|
|
485
|
+
assert_nil(phase1([], ['I']))
|
|
486
|
+
end
|
|
487
|
+
|
|
488
|
+
def test_simpe_match
|
|
489
|
+
assert_equal(['I.()V'], phase1(['I.()V'], []))
|
|
490
|
+
assert_equal(['I.(I)V'], phase1(['I.(I)V'], ['I']))
|
|
491
|
+
end
|
|
492
|
+
|
|
493
|
+
def test_arity
|
|
494
|
+
assert_equal(['I.(SI)V'], phase1(['I.(S)V', 'I.(SI)V', 'I.(SII)V'], ['S','I']))
|
|
495
|
+
end
|
|
496
|
+
|
|
497
|
+
def test_ambiguous
|
|
498
|
+
assert_equal(Set.new(%w(I.(SI)V I.(IS)V)),
|
|
499
|
+
Set.new(phase1(%w(I.(SI)V I.(IS)V), %w(S S))))
|
|
500
|
+
end
|
|
501
|
+
|
|
502
|
+
def test_ambiguity_resolution
|
|
503
|
+
assert_equal(['I.()V'], phase1(%w(@Z.()V I.()V), []))
|
|
504
|
+
end
|
|
505
|
+
|
|
506
|
+
def test_error_least_specific
|
|
507
|
+
error_member = Member.new(
|
|
508
|
+
Opcodes.ACC_PUBLIC, wrap('I'), 'foo', [ErrorType.new([['Error']])], wrap('I'),
|
|
509
|
+
MemberKind::METHOD)
|
|
510
|
+
# The method should match
|
|
511
|
+
assert_equal([error_member],
|
|
512
|
+
@lookup.phase1([error_member], [wrap('I')]).to_a)
|
|
513
|
+
# And be least specific
|
|
514
|
+
ok_member = make_method('I.(I)S')
|
|
515
|
+
assert_equal([ok_member],
|
|
516
|
+
@lookup.phase1([error_member, ok_member], [wrap('I')]).to_a)
|
|
517
|
+
end
|
|
518
|
+
end
|
|
519
|
+
|
|
520
|
+
class FieldTest < BaseMethodLookupTest
|
|
521
|
+
def setup
|
|
522
|
+
super
|
|
523
|
+
@a = FakeMirror.new('LA;')
|
|
524
|
+
@b = FakeMirror.new('LB;', @a)
|
|
525
|
+
@scope = JVMScope.new
|
|
526
|
+
@selfType = BaseTypeFuture.new
|
|
527
|
+
@selfType.resolved(@b)
|
|
528
|
+
@scope.selfType_set(@selfType)
|
|
529
|
+
end
|
|
530
|
+
|
|
531
|
+
def test_gather_fields
|
|
532
|
+
a_foo = @a.add_field("foo")
|
|
533
|
+
a_bar = @a.add_field("bar")
|
|
534
|
+
b_foo = @b.add_field("foo")
|
|
535
|
+
foos = @lookup.gatherFields(@b, 'foo').to_a
|
|
536
|
+
assert_equal([b_foo, a_foo], foos)
|
|
537
|
+
|
|
538
|
+
assert_equal([a_bar], @lookup.gatherFields(@b, 'bar').to_a)
|
|
539
|
+
end
|
|
540
|
+
|
|
541
|
+
def test_find_super_field
|
|
542
|
+
@a.add_field("foo")
|
|
543
|
+
future = @lookup.findMethod(@scope, @b, 'foo', [], nil, nil, false)
|
|
544
|
+
assert_equal("LA;", future.resolve.returnType.asm_type.descriptor)
|
|
545
|
+
end
|
|
546
|
+
|
|
547
|
+
def test_field_override
|
|
548
|
+
@a.add_field("foo")
|
|
549
|
+
@b.add_field("foo")
|
|
550
|
+
|
|
551
|
+
future = @lookup.findMethod(@scope, @b, 'foo', [], nil, nil, false)
|
|
552
|
+
assert_equal("LB;", future.resolve.returnType.asm_type.descriptor)
|
|
553
|
+
end
|
|
554
|
+
|
|
555
|
+
def test_inaccessible_overrides_accessible
|
|
556
|
+
@selfType.resolved(@a)
|
|
557
|
+
@a.add_field("foo", Opcodes.ACC_PUBLIC)
|
|
558
|
+
@b.add_field("foo", Opcodes.ACC_PRIVATE)
|
|
559
|
+
|
|
560
|
+
future = @lookup.findMethod(@scope, @b, 'foo', [], nil, nil, false)
|
|
561
|
+
assert_equal("LA;", future.resolve.returnType.asm_type.descriptor)
|
|
562
|
+
end
|
|
563
|
+
|
|
564
|
+
def test_inaccessible
|
|
565
|
+
@a.add_field("foo", Opcodes.ACC_PRIVATE)
|
|
566
|
+
future = @lookup.findMethod(@scope, @b, 'foo', [], nil, nil, false)
|
|
567
|
+
assert(future.resolve.isError, "Expected error, got #{future.resolve}")
|
|
568
|
+
end
|
|
569
|
+
|
|
570
|
+
def test_field_setter
|
|
571
|
+
@a.add_field("foo")
|
|
572
|
+
future = @lookup.findMethod(@scope, @a, 'foo_set', [@a], nil, nil, false)
|
|
573
|
+
end
|
|
574
|
+
end
|