#!/usr/bin/env python3
# Copyright 2017 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import logging
import re
import unittest
import function_signature
class AnalyzeTest(unittest.TestCase):
def testParseJavaFunctionSignature(self):
# Java method with no args
SIG = 'org.ClassName java.util.List getCameraInfo()'
actual = function_signature.ParseJava(SIG)
self.assertEqual('ClassName#getCameraInfo', actual[2])
self.assertEqual('org.ClassName#getCameraInfo(): java.util.List', actual[0])
self.assertEqual('org.ClassName#getCameraInfo', actual[1])
self.assertEqual(actual, function_signature.ParseJava(actual[0]))
# Java method with args
SIG = 'org.ClassName int readShort(int,int)'
actual = function_signature.ParseJava(SIG)
self.assertEqual('ClassName#readShort', actual[2])
self.assertEqual('org.ClassName#readShort', actual[1])
self.assertEqual('org.ClassName#readShort(int,int): int', actual[0])
self.assertEqual(actual, function_signature.ParseJava(actual[0]))
# Java <init> method
SIG = 'org.ClassName$Inner <init>(byte[])'
actual = function_signature.ParseJava(SIG)
self.assertEqual('ClassName$Inner#<init>', actual[2])
self.assertEqual('org.ClassName$Inner#<init>', actual[1])
self.assertEqual('org.ClassName$Inner#<init>(byte[])', actual[0])
self.assertEqual(actual, function_signature.ParseJava(actual[0]))
# Java Class
SIG = 'org.ClassName'
actual = function_signature.ParseJava(SIG)
self.assertEqual('ClassName', actual[2])
self.assertEqual('org.ClassName', actual[1])
self.assertEqual('org.ClassName', actual[0])
self.assertEqual(actual, function_signature.ParseJava(actual[0]))
# Java Field
SIG = 'org.ClassName some.Type mField'
actual = function_signature.ParseJava(SIG)
self.assertEqual('ClassName#mField', actual[2])
self.assertEqual('org.ClassName#mField', actual[1])
self.assertEqual('org.ClassName#mField: some.Type', actual[0])
self.assertEqual(actual, function_signature.ParseJava(actual[0]))
# Class merging: Method
SIG = 'org.NewClass int org.OldClass.readShort(int,int)'
actual = function_signature.ParseJava(SIG)
self.assertEqual('OldClass#readShort', actual[2])
self.assertEqual('org.OldClass#readShort', actual[1])
self.assertEqual('org.NewClass#org.OldClass.readShort(int,int): int',
actual[0])
self.assertEqual(actual, function_signature.ParseJava(actual[0]))
# Class merging: Field
SIG = 'org.NewClass some.Type org.OldClass.mField'
actual = function_signature.ParseJava(SIG)
self.assertEqual('OldClass#mField', actual[2])
self.assertEqual('org.OldClass#mField', actual[1])
self.assertEqual('org.NewClass#org.OldClass.mField: some.Type', actual[0])
self.assertEqual(actual, function_signature.ParseJava(actual[0]))
def testParseFunctionSignature(self):
def check(ret_part, name_part, params_part, after_part='',
name_without_templates=None):
if name_without_templates is None:
name_without_templates = re.sub(r'<.*?>', '<>', name_part) + after_part
signature = ''.join((name_part, params_part, after_part))
got_full_name, got_template_name, got_name = (
function_signature.Parse(signature))
self.assertEqual(name_without_templates, got_name)
self.assertEqual(name_part + after_part, got_template_name)
self.assertEqual(name_part + params_part + after_part, got_full_name)
if ret_part:
signature = ''.join((ret_part, name_part, params_part, after_part))
got_full_name, got_template_name, got_name = (
function_signature.Parse(signature))
self.assertEqual(name_without_templates, got_name)
self.assertEqual(name_part + after_part, got_template_name)
self.assertEqual(name_part + params_part + after_part, got_full_name)
check('bool ',
'foo::Bar<unsigned int, int>::Do<unsigned int>',
'(unsigned int)')
check('base::internal::CheckedNumeric<int>& ',
'base::internal::CheckedNumeric<int>::operator+=<int>',
'(int)')
check('base::internal::CheckedNumeric<int>& ',
'b::i::CheckedNumeric<int>::MathOp<b::i::CheckedAddOp, int>',
'(int)')
check('', '(anonymous namespace)::GetBridge', '(long long)')
check('', 'operator delete', '(void*)')
check('', 'b::i::DstRangeRelationToSrcRangeImpl<long long, long long, '
'std::__ndk1::numeric_limits, (b::i::Integer)1>::Check',
'(long long)')
check('', 'cc::LayerIterator::operator cc::LayerIteratorPosition const',
'()',
' const')
check('decltype ({parm#1}((SkRecords::NoOp)())) ',
'SkRecord::Record::visit<SkRecords::Draw&>',
'(SkRecords::Draw&)',
' const')
check('', 'base::internal::BindStateBase::BindStateBase',
'(void (*)(), void (*)(base::internal::BindStateBase const*))')
check('int ', 'std::__ndk1::__c11_atomic_load<int>',
'(std::__ndk1::<int> volatile*, std::__ndk1::memory_order)')
check('std::basic_ostream<char, std::char_traits<char> >& ',
'std::operator<< <std::char_traits<char> >',
'(std::basic_ostream<char, std::char_traits<char> >&, char)',
name_without_templates='std::operator<< <>')
check('',
'std::basic_istream<char, std::char_traits<char> >'
'::operator>>',
'(unsigned int&)',
name_without_templates='std::basic_istream<>::operator>>')
check('',
'std::operator><std::allocator<char> >', '()',
name_without_templates='std::operator><>')
check('',
'std::operator>><std::allocator<char> >',
'(std::basic_istream<char, std::char_traits<char> >&)',
name_without_templates='std::operator>><>')
check('',
'std::basic_istream<char>::operator>', '(unsigned int&)',
name_without_templates='std::basic_istream<>::operator>')
check('v8::internal::SlotCallbackResult ',
'v8::internal::UpdateTypedSlotHelper::UpdateCodeTarget'
'<v8::PointerUpdateJobTraits<(v8::Direction)1>::Foo(v8::Heap*, '
'v8::MemoryChunk*)::{lambda(v8::SlotType, unsigned char*)#2}::'
'operator()(v8::SlotType, unsigned char*, unsigned char*) '
'const::{lambda(v8::Object**)#1}>',
'(v8::RelocInfo, v8::Foo<(v8::PointerDirection)1>::Bar(v8::Heap*)::'
'{lambda(v8::SlotType)#2}::operator()(v8::SlotType) const::'
'{lambda(v8::Object**)#1})',
name_without_templates=(
'v8::internal::UpdateTypedSlotHelper::UpdateCodeTarget<>'))
check('',
'WTF::StringAppend<WTF::String, WTF::String>::operator WTF::String',
'()',
' const')
# Make sure []s are not removed from the name part.
check('', 'Foo', '()', ' [virtual thunk]')
# Template function that accepts an anonymous lambda.
check('',
'blink::FrameView::ForAllNonThrottledFrameViews<blink::FrameView::Pre'
'Paint()::{lambda(FrameView&)#2}>',
'(blink::FrameView::PrePaint()::{lambda(FrameView&)#2} const&)', '')
# Test with multiple template args.
check('int ', 'Foo<int()>::bar<a<b> >', '()',
name_without_templates='Foo<>::bar<>')
# SkArithmeticImageFilter.cpp has class within function body. e.g.:
# ArithmeticFP::onCreateGLSLInstance() looks like:
# class ArithmeticFP {
# GrGLSLFragmentProcessor* onCreateGLSLInstance() const {
# class GLSLFP {
# void emitCode(EmitArgs& args) { ... }
# };
# ...
# }
# };
SIG = '(anonymous namespace)::Foo::Baz() const::GLSLFP::onData(Foo, Bar)'
got_full_name, got_template_name, got_name = (
function_signature.Parse(SIG))
self.assertEqual('(anonymous namespace)::Foo::Baz', got_name)
self.assertEqual('(anonymous namespace)::Foo::Baz', got_template_name)
self.assertEqual(SIG, got_full_name)
# Top-level lambda.
# Note: Inline lambdas do not seem to be broken into their own symbols.
SIG = 'cc::{lambda(cc::PaintOp*)#63}::_FUN(cc::PaintOp*)'
got_full_name, got_template_name, got_name = (
function_signature.Parse(SIG))
self.assertEqual('cc::$lambda#63', got_name)
self.assertEqual('cc::$lambda#63', got_template_name)
self.assertEqual('cc::$lambda#63(cc::PaintOp*)', got_full_name)
SIG = 'cc::$_63::__invoke(cc::PaintOp*)'
got_full_name, got_template_name, got_name = (
function_signature.Parse(SIG))
self.assertEqual('cc::$lambda#63', got_name)
self.assertEqual('cc::$lambda#63', got_template_name)
self.assertEqual('cc::$lambda#63(cc::PaintOp*)', got_full_name)
# Data members
check('', 'blink::CSSValueKeywordsHash::findValueImpl', '(char const*)',
'::value_word_list')
check('', 'foo::Bar<Z<Y> >::foo<bar>', '(abc)', '::var<baz>',
name_without_templates='foo::Bar<>::foo<>::var<>')
# ABI Tag Attributes
SIG = 'std::make_unique[abi:v15000]<Foo>(Bar const*&)'
got_full_name, got_template_name, got_name = function_signature.Parse(SIG)
self.assertEqual('std::make_unique<>', got_name)
self.assertEqual('std::make_unique<Foo>', got_template_name)
self.assertEqual(SIG, got_full_name)
SIG = 'foo::kBar[abi:baz]'
got_full_name, got_template_name, got_name = function_signature.Parse(SIG)
self.assertEqual('foo::kBar', got_name)
self.assertEqual('foo::kBar', got_template_name)
self.assertEqual(SIG, got_full_name)
# Make sure operator[] is not considered an attribute.
check('', 'foo::operator[]', '(abc)')
SIG = 'foo<char []>::operator[][abi:v1500]<Bar[99]>()'
got_full_name, got_template_name, got_name = function_signature.Parse(SIG)
self.assertEqual('foo<>::operator[]<>', got_name)
self.assertEqual('foo<char []>::operator[]<Bar[99]>', got_template_name)
self.assertEqual(SIG, got_full_name)
if __name__ == '__main__':
logging.basicConfig(level=logging.DEBUG,
format='%(levelname).1s %(relativeCreated)6d %(message)s')
unittest.main()