JesTracePaster - 在源文件中添加方法入口日志的工具
这个简单的工具将在源代码文件中添加方法入口日志。

引言
JesTracePaster
是一个简单的应用程序,可用于在源代码文件中添加方法入口日志。当您有大量代码需要学习操作顺序时,这样的工具非常有用。手动在所有方法中添加跟踪信息将非常耗时。这个小工具 JesTracePaster
可以在这种情况下帮助您。
背景
我的一个朋友收到一个示例图像处理应用程序作为参考。虽然它只是一个示例,但代码相当复杂,而且他不太熟悉这项技术。所以他决定可以向大约 500 个源文件添加跟踪信息,并检查操作顺序,以便了解该应用程序的主要实体。但是,向 500 个文件添加跟踪信息本身就可能需要一周时间。当时,我正在努力开发 JesInclAnalyzer
(一个从源文件中删除不需要的头文件包含的工具;已发布在 CodeProject 上),发现 JesInclAnalyzer
中的一些类(经过一些修改)可以用来开发一个简单的应用程序,该应用程序可以将方法入口日志添加到源文件中的类方法中。
使用工具/代码
简单的文件操作和文本处理用于实现 JesTracePaster
。在“日志宏/函数/方法”编辑框中,输入用于记录的宏、函数或方法(例如:OutputDebugString
)。如果此编辑框留空,将使用 OutputDebugString
进行记录。在“源文件”编辑框中,输入要更新的源文件的路径。多个路径可以用“;”分隔。单击“更新”按钮。该工具将通过添加方法入口日志来更新源文件。处理状态将在主对话框中更新。请注意,该工具不会处理“只读”文件。它将为“只读”文件提供“访问被拒绝”错误消息。此外,该工具不适用于 C 风格的函数和在头文件中定义的方法。
首先,该工具借助 JesCPPIterator
类创建给定路径中可用源文件的列表。方法 bool JesCPPIterator::PopulateFileList( const CStringArray& Paths_i, bool bSrcFiles_i )
使用 CFileFind
创建源文件列表。源文件保存在 CStringArray
成员中,方法 bool JesCPPIterator::GetNextFile( CString& csSrcFile_o )
逐个返回文件名。我没有充分的理由向您解释为什么我没有从 CStringArray
派生此类,而是将其包装起来。我所做的可能不是一个好的设计。
类 JesFileProcessor
负责使用跟踪信息更新文件。方法 void JesFileProcessor::UpdateTraces( const CString& csLogMethod_i )
跳过单行和多行注释以提高效率。此方法检查“::[方法名](
”模式以修复方法起始位置;检查“{
”以修复日志插入点。一旦写入入口日志,将跳过代码行,直到方法块终止。这是基于大括号的配对完成的。以下代码片段实现了此逻辑:
while( m_SrcFile.ReadString( csLine ))
{
// Mark and skip Multi-line comment start
static const CString MULTI_LINE_COMMENT_END_SYMBOL = _T( "*/" );
if( !bMultiLineComment )
{
static const CString MULTI_LINE_COMMENT_SYMBOL = _T( "/*" );
csLine.TrimLeft();
csLine.TrimRight();
int nMLCmntStartIdx = csLine.Find( MULTI_LINE_COMMENT_SYMBOL );
int nMLCmntEndIdx = csLine.Find( MULTI_LINE_COMMENT_END_SYMBOL );
if( ( -1 != nMLCmntStartIdx ) &&
( -1 == nMLCmntEndIdx ))
{
bMultiLineComment = true;
continue;
}
else if( ( 0 == nMLCmntStartIdx ) &&
(( csLine.GetLength() - 1 ) == nMLCmntEndIdx ))
{
continue;
}
else
{
// Do nothing
}
}
else
{
if( -1 != csLine.Find( MULTI_LINE_COMMENT_END_SYMBOL ))
{
bMultiLineComment = false;
continue;
}
else
{
continue;
}
}
// Skip single line comments
static const CString SINGLE_LINE_COMMENT_SYMBOL = _T( "//" );
if( -1 != csLine.Find( SINGLE_LINE_COMMENT_SYMBOL ))
{
continue;
}
const static TCHAR EXP_LINE_END = _T( ';' );
static const TCHAR BLOCK_START = _T( '{' );
if( nBraceCnt )
{
static const TCHAR BLOCK_END = _T( '}' );
int nBlockStartIdx = csLine.Find( BLOCK_START );
int nBlockEndIdx = csLine.Find( BLOCK_END );
bool bBracePairs = (( -1 != nBlockStartIdx ) && ( -1 != nBlockEndIdx )) ||
(( -1 == nBlockStartIdx ) && ( -1 == nBlockEndIdx ));
if( !bBracePairs )
{
if( -1 != nBlockStartIdx )
{
++nBraceCnt;
}
else if( -1 != nBlockEndIdx )
{
--nBraceCnt;
}
else
{
// Do nothing
}
}
continue;
}
if( bLogMsgCreated )
{
if( -1 != csLine.Find( BLOCK_START ))
{
DWORD dwLinePos = m_SrcFile.GetPosition();
UpdateLine( dwLinePos, csLogMsg );
csLogMsg.Empty();
m_SrcFile.Seek( m_dwCurPos, CFile::begin );
bLogMsgCreated = false;
nBraceCnt = 1;
}
continue;
}
// Check method start
const static CString SCOPE_SYMBOL = _T( "::" );
int nScopeStartIdx = csLine.Find( SCOPE_SYMBOL );
if( ( -1 != nScopeStartIdx ) &&
( -1 == csLine.Find( EXP_LINE_END )))
{
static const TCHAR METHOD_START = _T( '(' );
int nMethodStartIdx = csLine.Find( METHOD_START );
if( nScopeStartIdx > nMethodStartIdx )
{
continue;
}
static const TCHAR DATA_TYPE_DELIMITER = _T( ' ' );
static const TCHAR METHOD_END = _T( ')' );
static const TCHAR DOUBLE_INVERTED_QUOTE = _T( '\"' );
static const CString BLOCK_INDENTATION = _T( " " );
int nMethodNameStartIdx = csLine.Find( DATA_TYPE_DELIMITER );
// For constructors
if( ( -1 == nMethodNameStartIdx ) ||
( nMethodNameStartIdx > nMethodStartIdx ))
{
nMethodNameStartIdx = 0;
}
else
{
nMethodNameStartIdx += 1;
}
CString csMethodName = csLine.Mid( nMethodNameStartIdx,
nMethodStartIdx - nMethodNameStartIdx );
csLogMsg.Format( _T( "%s%s%c %s %c%s%c %c%c%c" ),
BLOCK_INDENTATION, csLogMethod_i, METHOD_START,
_T( "_T(" ), DOUBLE_INVERTED_QUOTE,
csMethodName, DOUBLE_INVERTED_QUOTE,
METHOD_END, METHOD_END, EXP_LINE_END );
bLogMsgCreated = true;
}
}
关注点
我花了很多时间来检查一个错误。当我用自己的源文件测试 JesTracePaster
时,我发现了这个错误。在 JesFileProcessor.cpp 中,方法...
void JesFileProcessor::UpdateTraces( const CString& csLogMethod_i )
...后面跟着方法...
void JesFileProcessor::UpdateLine( DWORD dwLinePos_i, const CString& csUpdateLine_i )
... 和...
void JesFileProcessor::ShowFileException()
这个错误的表现是,入口日志永远不会插入最后两个方法中。 出现错误的原因是以下代码行
static const CString MULTI_LINE_COMMENT_SYMBOL = _T( "/*" );
我没有修复这个错误,因为我认为这在正常情况下是一种非常罕见的可能性。 留给读者作为练习。
历史
- 版本 1.0 - 2009 年 3 月 11 日