【问题标题】:Get function name from text file base on line of code根据代码行从文本文件中获取函数名
【发布时间】:2017-04-01 03:53:56
【问题描述】:

我有一个名为“MyCpp.cpp”的 C++ 源代码,它位于:C:\MyCpp.cpp

...
5 string CplusplusWarningFunction()
6 {
7   int a = 69;
8   int b = a + 1;
9   a = b;
10  b = 69;
11  return "42 is the answer";
12 }
...

现在我想写一个这样的C#函数

void CodeAnalyzer()
{
    string path = @"C:\MyCpp.cpp";
    int line = 11;
    IEnumerable<string> loc = File.ReadLines(path);

    string code = loc.ElementAt(line-1);//Yes, it is 'return "42 is the answer";', good job!
    string functionFullName = "???";//This suppose to be the string 'CplusplusWarningFunction()', but How to do it???
    MessageBox.Show(string.Format("The code {0} at line {1} is in function {2}",code,line,functionFullName));
}

如何获取函数名来替换字符串“???”在上面的 C# 代码中?

我知道这可以做到,因为 MS 的 FxCop 可以做到,有点(FxCop 分析编译的目标代码,而不是原始源代码)。好吧,如果编译的目标代码可以完成,为什么不是原始源代码。

而Visual Studio可以像下图那样做,我希望有一种方法可以访问Visual Studio API:

感谢阅读。

【问题讨论】:

  • loc.ElementAt(5) ?或 4 - 当你调用它时不确定它是否从零开始
  • 解析 C++ 比解析 C# 难很多。 (事实上​​,C# 的设计目标之一是创建一种更容易被工具解析的常规语言。)我强烈建议您考虑使用类似 LLVM 项目的东西来添加钩子,以便为 C++ 添加合适的钩子编译器。另请注意,FxCop 是一个多人年的项目 - 这不是一个学生可以在几个月内完成的事情。
  • @mmcrae 我认为这个想法是 OP 希望它适用于不同的代码文件和不同的行号。
  • 其实我有几个理想,你看,在Visual Studio中,当你把你的插入符号放在C++源代码中时,Visual Studio给你函数名,我想一定有办法像 Visual Studio 一样获取函数名称。
  • 或者像 Pvs studio viva64 一样,也许我们可以创建一个扩展,这样我们就可以访问 Visual Studio API。

标签: c# c++ text static analysis


【解决方案1】:

鉴于只有一个功能,你可以尝试每一行

//do this in a foreach loop that will iterate through every line
string functionName;
if (line.Split(' ').Where(x => x.Contains("()") && !x.Contains(".")).Count() > 0)
{
    functionName = line.Split(' ').Where(x => x.Contains("()") && !x.Contains(".")).First();
}

现在这将适用于您的示例代码,但这也是非常基本的,我相信在很多情况下这不起作用。不过,这可能不是一个糟糕的起点。

【讨论】:

    【解决方案2】:

    我想出了一个这样的代码,到目前为止还不错。

    class CppFunction
    {
        public string FunctionName { get; set; }
        public int StartLine { get; set; }
        public int EndLines { get; set; }
    }
    
    List<CppFunction> AnalyzeCpp(string path)
    {
        List<CppFunction> lstCppFunc = new List<CppFunction>();
    
        IEnumerable<string> loc = File.ReadLines(path, encode);
    
        string[] locNoCom = RemoveComment(loc);
        RemoveIfdefineDebug(locNoCom);
        int level = 0;
    
        CppFunction crtFunc = null;
        int lineCount = 0;
        StringBuilder builder = new StringBuilder();
        bool startName = false;
        string builderToString;
        string lastLine = "";
        foreach (string line in locNoCom)
        {
            lineCount++;
            if (string.IsNullOrWhiteSpace(line))
            {
                lastLine = line;
                continue;
            }
    
            if (level <= 0)
            {
                if (line.Contains('('))
                {
                    crtFunc = new CppFunction();
                    if (line.Trim().IndexOf('(') == 0)
                        builder.Append(lastLine);
                    builder.AppendLine(line);
                    crtFunc.StartLine = lineCount;
                    startName = true;
                }
                if (startName)
                {
                    builderToString = builder.ToString();
                    if (line != builderToString.Replace("\r\n",string.Empty))
                        builder.AppendLine(line);
                    if (line.Contains(')'))
                    {
                        startName = false;
                        if (crtFunc != null)
                            crtFunc.FunctionName = builder.ToString();
                        builder.Clear();
                    }
                }
            }
    
            if(line.Contains('{'))
            {
                foreach(char c in line)
                {
                    if (c == '{')
                        level++;
                }
            }
            if(line.Contains('}'))
            {
                foreach (char c in line)
                {
                    if (c == '}')
                        level--;
                }
                if (crtFunc != null && level <= 0)
                {
                    crtFunc.EndLines = lineCount;
                    lstCppFunc.Add(crtFunc);
                    crtFunc = null;
                    level = 0;
                }
            }
            lastLine = line;
        }
    
        return lstCppFunc;
    }
    

    现在我们有了函数列表及其起始行、结束行,当我们得到代码行时,我们可以检查它是否在哪个函数之间,然后 BAM - 我们得到了函数行。

    编辑: 我们还需要去掉评论来增加正义感

    string[] RemoveComment(IEnumerable<string> loc)
    {
        string[] line = loc.ToArray();
        bool startComment = false;
        int startComPos=0;
        int endComPos=-1;
        int count = line.Length;
        string comment;
    
        bool mistakeComment;
    
        int multiCommentStart, multiCommentEnd;
    
        for(int i=0;i<count;i++)
        {
            if (string.IsNullOrWhiteSpace(line[i]))
                continue;
            if (line[i].Contains("//"))
            {
                mistakeComment = false;
                if(line[i].Contains("*//*"))//Case mistake /**//**/ with //
                {
                    if ((line[i].IndexOf("//") - line[i].IndexOf("*//*")) == 1)
                    {
                        mistakeComment = true;
                    }
                }
    
                if(!mistakeComment)
                {
                    comment = line[i].Substring(line[i].IndexOf("//"));
                    line[i] = line[i].Replace(comment, string.Empty);
                }
            }
            if(line[i].Contains("/*"))
            {
                startComment = true;
                startComPos = line[i].IndexOf("/*");
                endComPos = -1;
            }
            else
            {
                startComPos = 0;
            }
    
            if (startComment)
            {
                if(!string.IsNullOrEmpty(line[i]))
                {
                    if (line[i].Contains("*/"))
                    {
                        startComment = false;
                        endComPos = line[i].IndexOf("*/", startComPos);
                    }
                    else
                        endComPos = -1;
                    if (endComPos == -1)
                    {
                        comment = line[i].Substring(startComPos);
                        line[i] = line[i].Replace(comment, string.Empty);
                    }
                    else
                    {
                        comment = line[i].Substring(startComPos, endComPos - startComPos + 2);
                        line[i] = line[i].Replace(comment, string.Empty);
                    }
                }
            }
    
            if (line[i].Contains("/*"))
            while((multiCommentStart = line[i].IndexOf("/*")) >= 0 &&
                (multiCommentEnd = line[i].IndexOf("*/")) >= 0 &&
                multiCommentEnd > multiCommentStart)
            {
                comment = line[i].Substring(multiCommentStart, multiCommentEnd - multiCommentStart + 2);
                line[i] = line[i].Replace(comment, string.Empty);
            }
        }
        return line;
    }
    

    哦,我们还需要删除 Debug 代码

    void RemoveIfdefineDebug(string[] linesCode)
    {
        bool startRemove = false;
        for(int i=0;i<linesCode.Length;i++)
        {
            if(startRemove)
            {
                if (linesCode[i].Contains("#endif"))
                {
                    startRemove = false;
                }
                else
                    linesCode[i] = string.Empty;
            }
            if (linesCode[i].Contains("#ifdef "))
            {
                startRemove = true;
            }
        }
    }
    

    最后是main函数

    string GetCodeAndFunctionName(string path, int line)
    {
        List<CppFunction> lstCppFunc = AnalyzeCpp(path);
        foreach(CppFunction func in lstCppFunc)
        {
            if(func.EndLines >= line && func.StartLine <= line)
            {
                return func.FunctionName;
            }
        }
        return "x";
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-10-07
      • 1970-01-01
      • 2013-06-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-01
      相关资源
      最近更新 更多