diff --git a/platform/smRunner/src/com/intellij/execution/testframework/sm/FileUrlProvider.java b/platform/smRunner/src/com/intellij/execution/testframework/sm/FileUrlProvider.java index f04e3a79d6cb..e74b15771955 100644 --- a/platform/smRunner/src/com/intellij/execution/testframework/sm/FileUrlProvider.java +++ b/platform/smRunner/src/com/intellij/execution/testframework/sm/FileUrlProvider.java @@ -30,7 +30,6 @@ import com.intellij.util.io.URLUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -49,19 +48,29 @@ public class FileUrlProvider implements SMTestLocator, DumbAware { return Collections.emptyList(); } - final String normalizedPath = path.replace(File.separatorChar, '/'); - - final int lineNoSeparatorIndex = normalizedPath.lastIndexOf(':'); - final String filePath; final int lineNumber; - // if line is specified - if (lineNoSeparatorIndex > 3) { // on Windows, paths start with /C: and that colon is not a line number separator - lineNumber = StringUtil.parseInt(normalizedPath.substring(lineNoSeparatorIndex + 1), -1); - filePath = normalizedPath.substring(0, lineNoSeparatorIndex); + final int columnNumber; + + int lastColonIndex = path.lastIndexOf(':'); + if (lastColonIndex > 3) { // on Windows, paths start with /C: and that colon is not a line number separator + int lastValue = StringUtil.parseInt(path.substring(lastColonIndex + 1), -1); + int penultimateColonIndex = path.lastIndexOf(':', lastColonIndex - 1); + if (penultimateColonIndex > 3) { + int penultimateValue = StringUtil.parseInt(path.substring(penultimateColonIndex + 1, lastColonIndex), -1); + filePath = path.substring(0, penultimateColonIndex); + lineNumber = penultimateValue; + columnNumber = lineNumber <= 0 ? -1 : lastValue; + } + else { + filePath = path.substring(0, lastColonIndex); + lineNumber = lastValue; + columnNumber = -1; + } } else { + filePath = path; lineNumber = -1; - filePath = normalizedPath; + columnNumber = -1; } // Now we should search file with most suitable path // here path may be absolute or relative @@ -73,20 +82,27 @@ public class FileUrlProvider implements SMTestLocator, DumbAware { final List locations = new ArrayList<>(2); for (VirtualFile file : virtualFiles) { - locations.add(createLocationFor(project, file, lineNumber)); + locations.add(createLocationFor(project, file, lineNumber, columnNumber)); } return locations; } + @Nullable + public static Location createLocationFor(@NotNull Project project, @NotNull VirtualFile virtualFile, int lineNum) { + return createLocationFor(project, virtualFile, lineNum, -1); + } + /** * @param project Project instance * @param virtualFile VirtualFile instance to locate * @param lineNum one-based line number to locate inside {@code virtualFile}, * a non-positive line number doesn't change text caret position inside the file + * @param columnNum one-based column number to locate inside {@code virtualFile}, + * a non-positive column number doesn't change text caret position inside the file * @return Location instance, or null if not found */ @Nullable - public static Location createLocationFor(@NotNull Project project, @NotNull VirtualFile virtualFile, int lineNum) { + public static Location createLocationFor(@NotNull Project project, @NotNull VirtualFile virtualFile, int lineNum, int columnNum) { final PsiFile psiFile = PsiManager.getInstance(project).findFile(virtualFile); if (psiFile == null) { return null; @@ -100,19 +116,14 @@ public class FileUrlProvider implements SMTestLocator, DumbAware { return null; } - final int lineCount = doc.getLineCount(); - final int lineStartOffset; - final int endOffset; - if (lineNum <= lineCount) { - lineStartOffset = doc.getLineStartOffset(lineNum - 1); - endOffset = doc.getLineEndOffset(lineNum - 1); - } else { - // unknown line - lineStartOffset = 0; - endOffset = doc.getTextLength(); + if (lineNum > doc.getLineCount()) { + return PsiLocation.fromPsiElement(psiFile); } + + final int lineStartOffset = doc.getLineStartOffset(lineNum - 1); + final int endOffset = doc.getLineEndOffset(lineNum - 1); - int offset = lineStartOffset; + int offset = Math.min(lineStartOffset + Math.max(columnNum - 1, 0), endOffset); PsiElement elementAtLine = null; while (offset <= endOffset) { elementAtLine = psiFile.findElementAt(offset); diff --git a/platform/smRunner/testSrc/com/intellij/execution/testframework/sm/FileUrlLocationTest.java b/platform/smRunner/testSrc/com/intellij/execution/testframework/sm/FileUrlLocationTest.java index 52e1aba1425d..43bc1e454c34 100644 --- a/platform/smRunner/testSrc/com/intellij/execution/testframework/sm/FileUrlLocationTest.java +++ b/platform/smRunner/testSrc/com/intellij/execution/testframework/sm/FileUrlLocationTest.java @@ -31,16 +31,21 @@ public class FileUrlLocationTest extends LightPlatformCodeInsightFixtureTestCase "my_example_spec.xml", "\n" + "\n" + - " \n" + + " \n" + "\n" + "\n").getVirtualFile(); - doTest(1, file.getPath(), 2); - doTest(16, file.getPath(), 3); + doTest(1, file.getPath(), 2, -1); + doTest(16, file.getPath(), 3, -1); + doTest(2, file.getPath(), 2, 5); + doTest(19, file.getPath(), 3, 8); + doTest(0, file.getPath(), 100, -1); + doTest(11, file.getPath(), 2, 100); } - private void doTest(int expectedOffset, String filePath, int lineNum) { - SMTestProxy testProxy = new SMTestProxy("myTest", false, "file://" + filePath + ":" + lineNum); + private void doTest(int expectedOffset, String filePath, int lineNum, int columnNumber) { + SMTestProxy testProxy = new SMTestProxy("myTest", false, "file://" + filePath + ":" + lineNum + + (columnNumber > 0 ? (":" + columnNumber) : "")); testProxy.setLocator(FileUrlProvider.INSTANCE); Location location = testProxy.getLocation(getProject(), GlobalSearchScope.allScope(getProject()));