crashanalysercmd/PerfToolsSharedLibraries/Engine/SymbianUtils/SourceParser/Parsers/ParserSrcMethod.cs
author Matti Laitinen <matti.t.laitinen@nokia.com>
Thu, 11 Feb 2010 15:50:58 +0200
changeset 0 818e61de6cd1
permissions -rw-r--r--
Add initial version of Crash Analyser cmdline under EPL

/*
* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). 
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
* 
* Description:
*
*/
using System;
using System.Collections.Generic;
using System.Text;
using SymbianUtils.SourceParser.Objects;
using SymbianUtils.SourceParser.Parsers;

namespace SymbianUtils.SourceParser.Parsers
{
    public class ParserSrcMethod
    {
        #region Constructors
        public ParserSrcMethod()
        {
        }
        #endregion

        #region API
        public SrcMethod Parse( ref string aText )
        {
            SrcMethod ret = null;
            //
            if ( aText.Length > 0 )
            {
                string parameters = string.Empty;
                //
                if ( ContainsParameters( aText ) )
                {
                    // This leaves modifiers intact
                    parameters = ExtractParameters( ref aText );
                }

                // Look for the class separator. If we find that, then everything after
                // it is the method name.
                //
                // If no class separator exists, then we treat the whole thing as the method
                // name.
                int pos = aText.IndexOf( SrcClass.KClassSeparator );

                // By default, treat the whole text as the class name
                string methodText = aText;
                if ( pos >= 0 )
                {
                    methodText = aText.Substring( pos + SrcClass.KClassSeparator.Length );
                    aText = aText.Substring( 0, pos + SrcClass.KClassSeparator.Length );
                }
                else
                {
                    // Everything was consumed...
                    aText = string.Empty;
                }

                // Make a new method. Work out if the method text
                // actually has any parameters
                ret = new SrcMethod();

                // Try to parse the modifiers. We extract that first
                // to leave us with just the method name and the parameters.
                bool hasModifier = ContainsModifier( methodText );
                if ( hasModifier )
                {
                    ParserSrcMethodModifier parser = new ParserSrcMethodModifier();
                    SrcMethodModifier modifier = parser.Parse( ref methodText );
                    if ( modifier != null )
                    {
                        ret.Modifier = modifier;
                    }
                }

                // Try to parse the parameters. We can also use this
                // to calculate the exact method name.
                if ( parameters.Length > 0 )
                {
                    ParserSrcMethodParameter parser = new ParserSrcMethodParameter();
                    parser.Parse( ref parameters, ret );
                }

                // What's left should be the method name followed by "()" if the
                // 'method' wasn't a label.
                if ( ContainsParameters( methodText ) )
                {
                    // Discard "()";
                    pos = methodText.LastIndexOf( "(" );
                    methodText = methodText.Substring( 0, pos );
                }

                ret.Name = methodText;
            }
            //
            return ret;
        }
        #endregion

        #region Properties
        #endregion

        #region Internal methods
        private static bool ContainsParameters( string aText )
        {
            // Search initiall for '(' - if that is found, then
            // we should also find a closing bracket.
            bool parameters = false;
            int openingBracketPos = aText.IndexOf( "(" );
            //
            if ( openingBracketPos > 0 )
            {
                // Should also be a closing bracket and it should
                // appear after the opening bracket
                int closingBracketPos = aText.LastIndexOf( ")" );
                parameters = ( closingBracketPos > openingBracketPos );
            }
            //
            return parameters;
        }

        private static bool ContainsModifier( string aText )
        {
            bool modifiers = false;

            int openingBracketPos = aText.IndexOf( "(" );
            if ( openingBracketPos >= 0 )
            {
                int closingBracketPos = openingBracketPos;
                SymbianUtils.Strings.StringParsingUtils.SkipToEndOfSection( ref aText, ref closingBracketPos, '(', ')' );

                if ( closingBracketPos > openingBracketPos )
                {
                    // everything here on is the modifier text;
                    string modifierText = aText.Substring( closingBracketPos + 1 );
                    modifiers = ( modifierText.Trim().Length > 0 );
                }
            }
            //
            return modifiers;
        }

        private static string ExtractParameters( ref string aText )
        {
            const string KOperatorChevronText = "operator <<";

            // DoAppendFormatList<TDes16, (int)2>(T1&, const T3&, std::__va_list, T2*)
            // DoAppendFormatList<TDes16, (int)2>(T1&, TBuf<(int)256>, std::__va_list, T2*)
            // Method<TDes16>::Wibble( something )
            // Method::Wibble( RPointerArray<HBufC> )
            // RTest::operator ()(int, int, const unsigned short*)
            // TDesC16::Left(int) const
            // CObjectCon::AtL(int) const
            // User::Panic(const TDesC16&, int)
            // operator <<(RWriteStream&, const unsigned char&)

            // Handle special case of "operator <<" confusing matters
            string workingText = aText;
            int operatorOpeningChevronPos = aText.IndexOf( KOperatorChevronText );
            if ( operatorOpeningChevronPos >= 0 )
            {
                aText = aText.Substring( 0, operatorOpeningChevronPos + KOperatorChevronText.Length );
                workingText = workingText.Substring( operatorOpeningChevronPos + KOperatorChevronText.Length );
            }
            else
            {
                aText = string.Empty;
            }

            string ret = string.Empty;
            //
            int closingPos = 0;
            int openingPos = 0;
            int templatePos = 0;
            //
            while ( openingPos >= 0 )
            {
                if ( templatePos >= 0 )
                    templatePos = workingText.IndexOf( "<", templatePos );
                openingPos = workingText.IndexOf( "(", openingPos );

                if ( templatePos >= 0 && templatePos < openingPos )
                {
                    // Template region appears before the next bracket. Skip
                    // over all characters until we hit the end of the template
                    // section
                    int endingPos = templatePos;
                    SymbianUtils.Strings.StringParsingUtils.SkipToEndOfSection( ref workingText, ref endingPos, '<', '>' );

                    if ( endingPos < 0 )
                    {
                        // Matching closing brace was never found - dealing with operator << ?
                        templatePos = -1;
                    }
                    else
                    {
                        // Something like DoAppendFormatList<TDes16, (int)2>(T1&, const T3&, std::__va_list, T2*) ???
                        templatePos = endingPos;
                        openingPos = endingPos;
                    }
                }
                else if ( openingPos >= 0 )
                {
                    // Skipped over any template nonsense. Work backward from the end 
                    // in order to locate start of parameters.
                    closingPos = workingText.LastIndexOf( ')' );
                    openingPos = closingPos;
                    SymbianUtils.Strings.StringParsingUtils.SkipToBeginningOfSection( ref workingText, ref openingPos, '(', ')' );

                    string parameters = workingText.Substring( openingPos + 1, ( closingPos - openingPos ) - 1 ).Trim();
                    ret = parameters;
                    workingText = workingText.Substring( 0, openingPos + 1 ) + workingText.Substring( closingPos );
                    aText = aText + workingText;
                    break;
                }
            }
            //
            return ret;
        }
        #endregion

        #region Data members
        #endregion
    }
}