Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get the name of the current and calling function in dart?

C# has:

System.Reflection.MethodBase.GetCurrentMethod().Name

Does Dart have something similar but returns results for both the function that is currently being run as well as the name of the function that called the currently run function.

like image 643
tensai Avatar asked Apr 22 '18 14:04

tensai


People also ask

How do you get the class name in darts?

String type = MyClass(). runtimeType. toString();

What is call function in DART?

In Dart, all functions are objects with type Function since Dart is a pure object-oriented language. All functions inherently have the call method. The call method is used to call a function like someFunction() . This is the same as writing someFunction.


3 Answers

I wrote a simple class that gives the current function and the caller function, but also, the file name, line number and column line from the StackTrace.current property.

Heres the code:

class CustomTrace {
  final StackTrace _trace;

  String fileName;
  String functionName;
  String callerFunctionName;
  int lineNumber;
  int columnNumber;

  CustomTrace(this._trace) {
    _parseTrace();
  }

  String _getFunctionNameFromFrame(String frame) {
    /* Just giving another nickname to the frame */
    var currentTrace = frame;

    /* To get rid off the #number thing, get the index of the first whitespace */
    var indexOfWhiteSpace = currentTrace.indexOf(' ');

    /* Create a substring from the first whitespace index till the end of the string */
    var subStr = currentTrace.substring(indexOfWhiteSpace);

    /* Grab the function name using reg expr */
    var indexOfFunction = subStr.indexOf(RegExp(r'[A-Za-z0-9]'));

    /* Create a new substring from the function name index till the end of string */
    subStr = subStr.substring(indexOfFunction);

    indexOfWhiteSpace = subStr.indexOf(' ');

    /* Create a new substring from start to the first index of a whitespace. This substring gives us the function name */
    subStr = subStr.substring(0, indexOfWhiteSpace);

    return subStr;
  }

  void _parseTrace() {
    /* The trace comes with multiple lines of strings, (each line is also known as a frame), so split the trace's string by lines to get all the frames */
    var frames = this._trace.toString().split("\n");

    /* The first frame is the current function */
    this.functionName = _getFunctionNameFromFrame(frames[0]);

    /* The second frame is the caller function */
    this.callerFunctionName = _getFunctionNameFromFrame(frames[1]);

    /* The first frame has all the information we need */
    var traceString = frames[0];

    /* Search through the string and find the index of the file name by looking for the '.dart' regex */
    var indexOfFileName = traceString.indexOf(RegExp(r'[A-Za-z]+.dart'));

    var fileInfo = traceString.substring(indexOfFileName);

    var listOfInfos = fileInfo.split(":");

    /* Splitting fileInfo by the character ":" separates the file name, the line number and the column counter nicely.
      Example: main.dart:5:12
      To get the file name, we split with ":" and get the first index
      To get the line number, we would have to get the second index
      To get the column number, we would have to get the third index
    */

    this.fileName = listOfInfos[0];
    this.lineNumber = int.parse(listOfInfos[1]);
    var columnStr = listOfInfos[2];
    columnStr = columnStr.replaceFirst(")", "");
    this.columnNumber = int.parse(columnStr);
  }
}

This class takes in a StackTrace object and reads its string and parse it.

How to use it (get the info):

void main() {
  CustomTrace programInfo = CustomTrace(StackTrace.current);

  print("Source file: ${programInfo.fileName}, function: ${programInfo.functionName}, caller function: ${programInfo.callerFunctionName}, current line of code since the instanciation/creation of the custom trace object: ${programInfo.lineNumber}, even the column(yay!): ${programInfo.columnNumber}");
}

The variable programInfo now has the function name, the caller function name, line number, column number and even the file name of the current program's execution.

You can print to the console the following:

print(StackTrace.current.toString());

And you will see how the string looks and be able to understand how i parse the string in order to get the information.

The simple benefit of this is that you dont have to install any library. I made this because i was doing a project just using Dart and i didnt want to add/install any third party library into my simple project. And you will end up with an object having all of the information by just calling the constructor. The downside of this is that it if Dart, for some reason, changes the string format of the stack trace somewhere in the future, this will no longer work BUT if this somehow happens, you can easily change how this class parses the frames*/

NOTE: This code by no means is the most optimize code, but it works :D. I would like to see some better implementations and abstractions.

like image 85
LuisDev99 Avatar answered Sep 18 '22 21:09

LuisDev99


There is no way to directly access the call stack in the Dart reflection library.

You can get a string representation of the stack trace, and then try to parse that:

var stack = StackTrace.current;
var stackString = "$stack"; // because the only method on StackTrace is toString.

The stack_trace package tries to do this for you for a number of known stack trace formats, so maybe:

import "package:stack_trace";
main() {
  print(Trace.current().frames[0].member);  // prints "main" unless minified.
}
like image 44
lrn Avatar answered Sep 21 '22 21:09

lrn


Tidied up @LuisDev99's answer a bit, optimizing for yourself:

class LoggerStackTrace {
  const LoggerStackTrace._({
    required this.functionName,
    required this.callerFunctionName,
    required this.fileName,
    required this.lineNumber,
    required this.columnNumber,
  });

  factory LoggerStackTrace.from(StackTrace trace) {
    final frames = trace.toString().split('\n');
    final functionName = _getFunctionNameFromFrame(frames[0]);
    final callerFunctionName = _getFunctionNameFromFrame(frames[1]);
    final fileInfo = _getFileInfoFromFrame(frames[0]);

    return LoggerStackTrace._(
      functionName: functionName,
      callerFunctionName: callerFunctionName,
      fileName: fileInfo[0],
      lineNumber: int.parse(fileInfo[1]),
      columnNumber: int.parse(fileInfo[2].replaceFirst(')', '')),
    );
  }

  final String functionName;
  final String callerFunctionName;
  final String fileName;
  final int lineNumber;
  final int columnNumber;

  static List<String> _getFileInfoFromFrame(String trace) {
    final indexOfFileName = trace.indexOf(RegExp('[A-Za-z]+.dart'));
    final fileInfo = trace.substring(indexOfFileName);

    return fileInfo.split(':');
  }

  static String _getFunctionNameFromFrame(String trace) {
    final indexOfWhiteSpace = trace.indexOf(' ');
    final subStr = trace.substring(indexOfWhiteSpace);
    final indexOfFunction = subStr.indexOf(RegExp('[A-Za-z0-9]'));

    return subStr
        .substring(indexOfFunction)
        .substring(0, subStr.substring(indexOfFunction).indexOf(' '));
  }

  @override
  String toString() {
    return 'LoggerStackTrace('
        'functionName: $functionName, '
        'callerFunctionName: $callerFunctionName, '
        'fileName: $fileName, '
        'lineNumber: $lineNumber, '
        'columnNumber: $columnNumber)';
  }
}
print(LoggerStackTrace.from(StackTrace.current).toString());
like image 22
Holofox Avatar answered Sep 20 '22 21:09

Holofox