@@ -119,13 +119,15 @@ class Function extends @function, Parameterized, TypeParameterized, StmtContaine
119119 override StmtContainer getEnclosingContainer ( ) { result = getEnclosingStmt ( ) .getContainer ( ) }
120120
121121 /** Gets the number of lines in this function. */
122- int getNumberOfLines ( ) { numlines ( this , result , _, _) }
122+ int getNumberOfLines ( ) {
123+ exists ( int sl , int el | getLocation ( ) .hasLocationInfo ( _, sl , _, el , _) | result = el - sl + 1 )
124+ }
123125
124126 /** Gets the number of lines containing code in this function. */
125- int getNumberOfLinesOfCode ( ) { numlines ( this , _ , result , _ ) }
127+ int getNumberOfLinesOfCode ( ) { result = LinesOfCode :: getNumCodeLines ( this ) }
126128
127129 /** Gets the number of lines containing comments in this function. */
128- int getNumberOfLinesOfComments ( ) { numlines ( this , _ , _ , result ) }
130+ int getNumberOfLinesOfComments ( ) { result = LinesOfComments :: getNumCommentLines ( this ) }
129131
130132 /** Gets the cyclomatic complexity of this function. */
131133 int getCyclomaticComplexity ( ) {
@@ -341,6 +343,118 @@ class Function extends @function, Parameterized, TypeParameterized, StmtContaine
341343 CanonicalFunctionName getCanonicalName ( ) { ast_node_symbol ( this , result ) }
342344}
343345
346+ /**
347+ * Provides predicates for computing lines-of-code information for functions.
348+ */
349+ private module LinesOfCode {
350+ /**
351+ * Holds if `tk` is interesting for the purposes of counting lines of code, that is, it might
352+ * contribute a line of code that isn't covered by any other token.
353+ *
354+ * A token is interesting if it is the first token on its line, or if it spans multiple lines.
355+ */
356+ private predicate isInteresting ( Token tk ) {
357+ exists ( int sl , int el | tk .getLocation ( ) .hasLocationInfo ( _, sl , _, el , _) |
358+ not tk .getPreviousToken ( ) .getLocation ( ) .getEndLine ( ) = sl
359+ or
360+ sl != el
361+ )
362+ }
363+
364+ /**
365+ * Gets the `i`th token in toplevel `tl`, but only if it is interesting.
366+ */
367+ pragma [ noinline]
368+ private Token getInterestingToken ( TopLevel tl , int i ) {
369+ result .getTopLevel ( ) = tl and
370+ result .getIndex ( ) = i and
371+ isInteresting ( result )
372+ }
373+
374+ /**
375+ * Holds if `f` covers tokens between indices `start` and `end` (inclusive) in toplevel `tl`.
376+ */
377+ predicate tokenRange ( Function f , TopLevel tl , int start , int end ) {
378+ tl = f .getTopLevel ( ) and
379+ start = f .getFirstToken ( ) .getIndex ( ) and
380+ end = f .getLastToken ( ) .getIndex ( )
381+ }
382+
383+ /**
384+ * Gets an interesting token belonging to `f`.
385+ */
386+ private Token getAnInterestingToken ( Function f ) {
387+ result = f .getFirstToken ( )
388+ or
389+ exists ( TopLevel tl , int start , int end | tokenRange ( f , tl , start , end ) |
390+ result = getInterestingToken ( tl , [ start .. end ] )
391+ )
392+ }
393+
394+ /**
395+ * Gets the line number of a line covered by `f` that contains at least one token.
396+ */
397+ private int getACodeLine ( Function f ) {
398+ exists ( Location loc | loc = getAnInterestingToken ( f ) .getLocation ( ) |
399+ result in [ loc .getStartLine ( ) .. loc .getEndLine ( ) ]
400+ )
401+ }
402+
403+ /**
404+ * Gets the number of lines of code of `f`.
405+ *
406+ * Note the special handling of empty locations; this is needed to correctly deal with
407+ * synthetic constructors.
408+ */
409+ int getNumCodeLines ( Function f ) {
410+ if f .getLocation ( ) .isEmpty ( ) then result = 0 else result = count ( getACodeLine ( f ) )
411+ }
412+ }
413+
414+ /**
415+ * Provides predicates for computing lines-of-comments information for functions.
416+ */
417+ private module LinesOfComments {
418+ /**
419+ * Holds if `tk` is interesting for the purposes of counting comments, that is,
420+ * if it is preceded by a comment.
421+ */
422+ private predicate isInteresting ( Token tk ) { exists ( Comment c | tk = c .getNextToken ( ) ) }
423+
424+ /**
425+ * Gets the `i`th token in `tl`, if it is interesting.
426+ */
427+ pragma [ noinline]
428+ private Token getToken ( TopLevel tl , int i ) {
429+ result .getTopLevel ( ) = tl and
430+ result .getIndex ( ) = i and
431+ isInteresting ( result )
432+ }
433+
434+ /**
435+ * Gets a comment inside function `f`.
436+ */
437+ private Comment getAComment ( Function f ) {
438+ exists ( TopLevel tl , int start , int end | LinesOfCode:: tokenRange ( f , tl , start , end ) |
439+ result .getNextToken ( ) = getToken ( tl , [ start + 1 .. end ] )
440+ )
441+ }
442+
443+ /**
444+ * Gets a line covered by `f` on which at least one comment appears.
445+ */
446+ private int getACommentLine ( Function f ) {
447+ exists ( Location loc | loc = getAComment ( f ) .getLocation ( ) |
448+ result in [ loc .getStartLine ( ) .. loc .getEndLine ( ) ]
449+ )
450+ }
451+
452+ /**
453+ * Gets the number of lines with at least one comment in `f`.
454+ */
455+ int getNumCommentLines ( Function f ) { result = count ( getACommentLine ( f ) ) }
456+ }
457+
344458/**
345459 * A method defined in a class or object expression.
346460 */
0 commit comments