tags:

views:

216

answers:

4

I have code that correctly finds the line number of an IMethod in Eclipse under Windows:

IMethod method= ...;
String source= type.getCompilationUnit().getSource();
int lineNumber= 1;
for (int i= 0; i < method.getSourceRange().getOffset(); i++)
    if (source.charAt(i) == Character.LINE_SEPARATOR)
     lineNumber++;

However, this doesn't work on the Mac, presume because the line separator character is different even though the source code it is operating on is the same.

  1. is there a built-in way to get the line number without having to traverse every character of the source? (seems like there should be but I couldn't find it)
  2. if not, is there a platform independent way to count line breaks in a string?

Thanks,

Kent Beck

A: 

You could wrap the String with a BufferedReader instance, which supports a readLine() method. This method presumably correctly parses any kind of separator.

Wouter Lievens
+3  A: 

I can't answer (1), but I'll give (2) a shot.

Oddly enough, I think your code was only working by coincidence. Character.LINE_SEPARATOR indicates a Unicode category; it isn't supposed to be the platform's newline character, but it just so happens to have the value 13, which (as you probably know) is '\r'. If I remember correctly, Macs since OS X have used '\n' for newlines, so this is why it doesn't work.

The way I've gotten the line separator character in the past is System.getProperty("line.separator"). This returns a String, so it might not be suitable. Since it seemed to work with '\r' on Windows, I'd guess that a simple check for '\n' would suffice as well. Alternatively, you could use a BufferedReader wrapped around a StringReader, as Wouter Lievens suggested.

Michael Myers
+1 for System.getProperty("line.separator")
matt b
A: 

You could use an IScanner built by a ToolFactory, as used in this class (not to count line, but still, it gives the idea)

Hopefully, the internal eclipse implementation of an IScanner will work correctly on any platform.

IBuffer buffer = imethod.getOpenable().getBuffer();
ISourceRange sourceRange = imethod.getSourceRange();
ISourceRange nameRange = imethod.getNameRange();
IScanner scanner = null; // delay initialization

if (sourceRange != null && nameRange != null) {
    if (scanner == null) {
        scanner= ToolFactory.createScanner(false, false, true, false);
        scanner.setSource(buffer.getCharacters());
    }
    scanner.resetTo(sourceRange.getOffset(), nameRange.getOffset());
} else {
    return 0 // no lines;
}
// use scanner to count lines
VonC
+1  A: 

I ended up using regex instead, because it was simpler. This makes the code O(n^2) in the number of methods I need to take in the file, but I expect this should be a small number so it's acceptable for now.

private int getMethodLineNumber(final IType type, IMethod method) throws JavaModelException {
    String source= type.getCompilationUnit().getSource();
    String sourceUpToMethod= source.substring(0, method.getSourceRange().getOffset());
    Pattern lineEnd= Pattern.compile("$", Pattern.MULTILINE | Pattern.DOTALL);
    return lineEnd.split(sourceUpToMethod).length;
}

Thank you all for the help.

Regards,

Kent

Kent Beck
It would be faster to make lineEnd a constant so it doesn't have to be compiled every time the method is invoked. Of course, with such a small pattern, that's not likely to make much difference.
Michael Myers