rust-code-analysis icon indicating copy to clipboard operation
rust-code-analysis copied to clipboard

Empty output when calculating metrics for this function in C

Open MartinLwx opened this issue 2 years ago • 5 comments

Description

I attempted to extract code metrics from a certain function, but the output turned out to be empty. I discovered that there are multiple nodes labeled as ERROR in AST. Is it caused by this?

Steps to reproduce

The command I tried

$ rust-code-analysis-cli --paths foo.c -m

The code

static YYACTIONTYPE
yy_find_shift_action(YYCODETYPE iLookAhead, /* The look-ahead token */
                     YYACTIONTYPE stateno   /* Current state number */
) {
  int i;

  if (stateno > YY_MAX_SHIFT)
    return stateno;
  assert(stateno <= YY_SHIFT_COUNT);
#if defined(YYCOVERAGE)
  yycoverage[stateno][iLookAhead] = 1;
#endif
  do {
    i = yy_shift_ofst[stateno];
    assert(i >= 0);
    /* assert( i+YYNTOKEN<=(int)YY_NLOOKAHEAD ); */
    assert(iLookAhead != YYNOCODE);
    assert(iLookAhead < YYNTOKEN);
    i += iLookAhead;
    if (i >= YY_NLOOKAHEAD || yy_lookahead[i] != iLookAhead) {
#ifdef YYFALLBACK
      YYCODETYPE iFallback; /* Fallback token */
      if (iLookAhead < sizeof(yyFallback) / sizeof(yyFallback[0]) &&
          (iFallback = yyFallback[iLookAhead]) != 0) {
#ifndef NDEBUG
        if (yyTraceFILE) {
          fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n", yyTracePrompt,
                  yyTokenName[iLookAhead], yyTokenName[iFallback]);
        }
#endif
        assert(yyFallback[iFallback] == 0); /* Fallback loop must terminate */
        iLookAhead = iFallback;
        continue;
      }
#endif
#ifdef YYWILDCARD
      {
        int j = i - iLookAhead + YYWILDCARD;
        if (
#if YY_SHIFT_MIN + YYWILDCARD < 0
            j >= 0 &&
#endif
#if YY_SHIFT_MAX + YYWILDCARD >= YY_ACTTAB_COUNT
            j < YY_ACTTAB_COUNT &&
#endif
            j < (int)(sizeof(yy_lookahead) / sizeof(yy_lookahead[0])) &&
            yy_lookahead[j] == YYWILDCARD && iLookAhead > 0) {
#ifndef NDEBUG
          if (yyTraceFILE) {
            fprintf(yyTraceFILE, "%sWILDCARD %s => %s\n", yyTracePrompt,
                    yyTokenName[iLookAhead], yyTokenName[YYWILDCARD]);
          }
#endif /* NDEBUG */
          return yy_action[j];
        }
      }
#endif /* YYWILDCARD */
      return yy_default[stateno];
    } else {
      return yy_action[i];
    }
  } while (1);
}

MartinLwx avatar Feb 23 '23 11:02 MartinLwx

Yep, this is probably a bug in the C grammar (maybe related to the preprocessor stuff).

Are you able to reduce the test case to the minimum?

marco-c avatar Feb 24 '23 11:02 marco-c

Yep, this is probably a bug in the C grammar (maybe related to the preprocessor stuff).

Are you able to reduce the test case to the minimum?

I made some revisions to the code by removing certain preprocessor parts and code lines. I'm not entirely certain if this was the correct approach, but I hope that it will be helpful.

static YYACTIONTYPE
yy_find_shift_action(YYCODETYPE iLookAhead, /* The look-ahead token */
                     YYACTIONTYPE stateno   /* Current state number */
) {
  do {
    if (i >= YY_NLOOKAHEAD || yy_lookahead[i] != iLookAhead) {
#ifdef YYWILDCARD
      {
        if (
#if YY_SHIFT_MAX + YYWILDCARD >= YY_ACTTAB_COUNT
            j < YY_ACTTAB_COUNT &&
#endif
            j < (int)(sizeof(yy_lookahead) / sizeof(yy_lookahead[0])) &&
            yy_lookahead[j] == YYWILDCARD && iLookAhead > 0) {
#ifndef NDEBUG
          if (yyTraceFILE) {
            fprintf(yyTraceFILE, "%sWILDCARD %s => %s\n", yyTracePrompt,
                    yyTokenName[iLookAhead], yyTokenName[YYWILDCARD]);
          }
#endif /* NDEBUG */
          return yy_action[j];
        }
      }
#endif /* YYWILDCARD */
      return yy_default[stateno];
    }
  } while (1);
}

MartinLwx avatar Feb 24 '23 15:02 MartinLwx

Are you sure this is the minimum amount of code to make it fail? Could you try removing more and more until you get to something that doesn't fail? Then you can show us the snippet of code right before the last modification that makes it fail, and the snippet of code after that modification.

marco-c avatar Feb 24 '23 15:02 marco-c

Are you sure this is the minimum amount of code to make it fail? Could you try removing more and more until you get to something that doesn't fail? Then you can show us the snippet of code right before the last modification that makes it fail, and the snippet of code after that modification.

Hi, sorry for that. This time I made more eager modification through trial and error. I believe that the code has been reduced to the most minimal amount possible.

The code before last modification that makes it fail:

static YYACTIONTYPE yy_find_shift_action() {
  do {
    if (yy_lookahead[i] != iLookAhead) {
#ifdef YYWILDCARD
      {
        if (
#if YY_SHIFT_MAX + YYWILDCARD >= YY_ACTTAB_COUNT
            j < YY_ACTTAB_COUNT &&
#endif
            yy_lookahead[j] == YYWILDCARD) {
#ifndef NDEBUG
          if (yyTraceFILE) {
            fprintf(yyTraceFILE, "%sWILDCARD %s", yyTracePrompt,
                    yyTokenName[iLookAhead]);
          }
#endif
        }
      }
#endif
    }
  } while (1);
}

Possible fix: Delete any inner #if... pairs(additional code has been omitted for brevity).

...
#ifdef YYWILDCARD
      {
        if (
            yy_lookahead[j] == YYWILDCARD) {
#ifndef NDEBUG
          if (yyTraceFILE) {
            fprintf(yyTraceFILE, "%sWILDCARD %s", yyTracePrompt,
                    yyTokenName[iLookAhead]);
          }
#endif
        }
      }
#endif
...

Possible fix: Remove the brackets(i.e {})

...
          if (yyTraceFILE) 
            fprintf(yyTraceFILE, "%sWILDCARD %s", yyTracePrompt,
                    yyTokenName[iLookAhead]);
...

Possible fix: Condense the function call into a single line

...
          if (yyTraceFILE) {
            fprintf(yyTraceFILE, "%sWILDCARD %s", yyTracePrompt, yyTokenName[iLookAhead]);
          }
...

Possible fix: Change the condition of if statement.

...
#if YY_SHIFT_MAX + YYWILDCARD >= YY_ACTTAB_COUNT
            j < YY_ACTTAB_COUNT
#endif
            ) {
...

MartinLwx avatar Feb 24 '23 16:02 MartinLwx

Thanks, that's better. I guess we could further reduce it by simplifying the statements (e.g. fprintf(yyTraceFILE, "%sWILDCARD %s", yyTracePrompt, yyTokenName[iLookAhead]); could be a single statement like int x = 0; or similar).

There is probably a but in the handling of macros.

marco-c avatar Mar 09 '23 11:03 marco-c