Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stacktrace analyzer window fixes #6841

Merged
merged 1 commit into from
Dec 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion java/java.navigation/manifest.mf
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/java/navigation/Bundle.pr
OpenIDE-Module-Requires: org.openide.windows.WindowManager
OpenIDE-Module-Specification-Version: 1.63
AutoUpdate-Show-In-Client: false

OpenIDE-Module-Java-Dependencies: Java > 11
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@
import org.netbeans.modules.parsing.spi.SchedulerTask;
import org.netbeans.modules.parsing.spi.TaskFactory;
import org.netbeans.modules.parsing.spi.TaskIndexingMode;
import org.openide.nodes.Node;

/**
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@
import javax.lang.model.type.ArrayType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Elements.Origin;
import org.netbeans.api.annotations.common.CheckForNull;
import org.netbeans.api.annotations.common.NonNull;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@
import org.netbeans.api.editor.mimelookup.MimeLookup;
import org.netbeans.api.editor.settings.FontColorNames;
import org.netbeans.api.editor.settings.FontColorSettings;
import org.netbeans.editor.EditorUI;

/**
* HTML documentation view.
Expand Down Expand Up @@ -118,6 +117,7 @@ public void run(){
});
}

@Override
protected EditorKit createDefaultEditorKit() {
// it is extremelly slow to init it
if (htmlKit == null){
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,19 +98,15 @@ public Component getListCellRendererComponent (
if (isSelected) {
sb.append("<style> a.val {text-decoration: underline; color: "+toRgbText(getForeground())+"} </style><body>");
}
String prefix = line.substring (0, link.getStartOffset ());
if (prefix.startsWith("at ")) {
prefix = "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;" + prefix;
}
sb.append (prefix);
sb.append ("<a class=\"val\" href=\"\">");
sb.append (line.substring (link.getStartOffset (), link.getEndOffset ()));
sb.append ("</a>");
sb.append (line.substring (link.getEndOffset ()));
sb.append ("</body></html>");
setText (sb.toString ());
sb.append(indentAt(escapeAngleBrackets(line.substring(0, link.getStartOffset())), "&nbsp;"));
sb.append("<a class=\"val\" href=\"\">");
sb.append(escapeAngleBrackets(line.substring(link.getStartOffset(), link.getEndOffset())));
sb.append("</a>");
sb.append(escapeAngleBrackets(line.substring(link.getEndOffset())));
sb.append("</body></html>");
setText(sb.toString ());
} else {
setText (line.trim ());
setText(indentAt(line.strip(), " "));
}

setEnabled (list.isEnabled ());
Expand Down Expand Up @@ -145,5 +141,13 @@ public Component getListCellRendererComponent (
private String toRgbText(Color c) {
return String.format("#%02x%02x%02x", c.getRed(), c.getGreen(), c.getBlue());
}

private String escapeAngleBrackets(String str) {
return str.replace("<", "&lt;");
}

private String indentAt(String str, String indent) {
return str.startsWith("at ") ? indent.repeat(8) + str : str;
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public AnalyzeStackAction() {
// putValue(SMALL_ICON, new ImageIcon(Utilities.loadImage(AnalyzeStackTopComponent.ICON_PATH, true)));
}

@Override
public void actionPerformed(ActionEvent evt) {
TopComponent win = AnalyzeStackTopComponent.findInstance();
win.open();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,8 @@ static void fillListModel(BufferedReader r, DefaultListModel model) {
String lastLine = null;
try {
while ((currentLine = r.readLine()) != null) {
currentLine = currentLine.trim();
// strip ANSI symbols just in case the terminal/clipboard hasn't done that
currentLine = currentLine.replaceAll("\u001B\\[[\\d;]*[^\\d;]", "").strip();
if (StackLineAnalyser.matches(currentLine)) {
if (lastLine != null) {
model.addElement(lastLine);
Expand Down
Copy link
Member Author

@mbien mbien Dec 14, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

recommend to enable ignore whitespace changes for reviewing this one - sorry about this

Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,9 @@
import javax.swing.text.StyledDocument;
import org.netbeans.api.annotations.common.CheckForNull;
import org.netbeans.api.annotations.common.NullAllowed;

import org.netbeans.api.java.classpath.ClassPath;
import org.netbeans.api.java.classpath.GlobalPathRegistry;
import org.netbeans.api.progress.ProgressHandle;
import org.netbeans.api.progress.ProgressHandleFactory;
import org.netbeans.spi.java.classpath.support.ClassPathSupport;
import org.openide.awt.StatusDisplayer;
import org.openide.cookies.EditorCookie;
Expand All @@ -57,11 +55,12 @@ class StackLineAnalyser {
private static final String IDENTIFIER =
"\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*"; // NOI18N
private static final Pattern LINE_PATTERN = Pattern.compile(
"at\\s" + // initial at // NOI18N
"at\\s+" + // initial at // NOI18N
"("+IDENTIFIER+"(?:\\."+IDENTIFIER+")*/)?" + // optional module name // NOI18N
"(("+IDENTIFIER+"(\\."+IDENTIFIER+")*)\\.)?("+IDENTIFIER+")" + // class name // NOI18N
"\\.("+IDENTIFIER+"|\\<init\\>|\\<clinit\\>)\\((?:"+IDENTIFIER+"(?:\\."+IDENTIFIER+")*/)?" +IDENTIFIER+"\\.?("+IDENTIFIER+ // method and file name // NOI18N
")\\:([0-9]*)\\)"); // line number // NOI18N
"\\.("+IDENTIFIER+"|\\<init\\>|\\<clinit\\>)\\s*"+ // method name
"\\((?:"+IDENTIFIER+"(?:\\."+IDENTIFIER+")*/)?"+IDENTIFIER+"(\\.(?:\\p{javaJavaIdentifierPart}+))?"+ // '(File.java' // NOI18N
"\\:([0-9]*)\\)"); // ':123)' // NOI18N
Comment on lines 57 to +63
Copy link
Member Author

@mbien mbien Dec 17, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the original goal was to add a few optional \\s* but this does also include a fix for https://github.com/apache/netbeans/pull/6640/files#r1377502665, since this didn't work before as pointed out by @dbalek in the linked review.

The file extension group is now optional (\\.(?:\\p{javaJavaIdentifierPart}+))? and matches more character types since extensions aren't real java identifiers. Tests cover this now too.


static boolean matches(String line) {
Matcher matcher = LINE_PATTERN.matcher(line);
Expand All @@ -71,7 +70,7 @@ static boolean matches(String line) {
static Link analyse(String line) {
Matcher matcher = LINE_PATTERN.matcher(line);
if (matcher.find()) {
int lineNumber = -1;
int lineNumber;
try {
lineNumber = Integer.parseInt(matcher.group(8));
} catch (NumberFormatException nfe) {
Expand All @@ -81,7 +80,7 @@ static Link analyse(String line) {
if (matcher.group(1) != null) {
moduleStart = matcher.start(1);
}
String ext = "." + matcher.group(7);
String ext = matcher.group(7);
if (matcher.group(2)==null ) {
return new Link(matcher.group(5),
lineNumber,
Expand Down Expand Up @@ -144,75 +143,67 @@ void show () {
resources.add(name + ".java"); //NOI18N
idx = name.lastIndexOf('$');
}
final ProgressHandle handle = ProgressHandleFactory.createHandle(
final ProgressHandle handle = ProgressHandle.createHandle(
NbBundle.getMessage(StackLineAnalyser.class, "TXT_OpeningSource", resources.get(0)));
handle.start();
RP.execute(
new Runnable() {
@Override
public void run() {
DataObject dobj = null;
try {
final ClassPath classPath = ClassPathSupport.createClassPath(
RP.execute(() -> {
DataObject dobj = null;
try {
final ClassPath classPath = ClassPathSupport.createClassPath(
GlobalPathRegistry.getDefault().getSourceRoots().toArray(new FileObject[0]));
for (String resource : resources) {
dobj = findDataObject(classPath.findResource(resource));
if (dobj != null)
break;
for (String resource : resources) {
dobj = findDataObject(classPath.findResource(resource));
if (dobj != null)
break;
}
} finally {
final DataObject dataObject = dobj;
Mutex.EVENT.readAccess(() -> {
try {
if (dataObject == null) {
StatusDisplayer.getDefault().setStatusText(
NbBundle.getMessage(StackLineAnalyser.class,
"AnalyzeStackTopComponent.sourceNotFound",
new Object[]{resources.get(0)}));
return;
}
} finally {
final DataObject dataObject = dobj;
Mutex.EVENT.readAccess(new Runnable() {
@Override
public void run() {
try {
if (dataObject == null) {
StatusDisplayer.getDefault().setStatusText(
NbBundle.getMessage(StackLineAnalyser.class,
"AnalyzeStackTopComponent.sourceNotFound",
new Object[]{resources.get(0)}));
return;
}
try {
EditorCookie editorCookie = (EditorCookie) dataObject.getCookie(EditorCookie.class);
LineCookie lineCookie = (LineCookie) dataObject.getCookie(LineCookie.class);
if (editorCookie != null && lineCookie != null && lineNumber != -1) {
StyledDocument doc = editorCookie.openDocument();
if (doc != null) {
if (lineNumber != -1) {
try {
Line l = lineCookie.getLineSet().getCurrent(lineNumber - 1);

if (l != null) {
l.show(Line.SHOW_GOTO);
return;
}
} catch (IndexOutOfBoundsException oob) {
//line number is no more valid, do not report as an error
StatusDisplayer.getDefault().setStatusText(
NbBundle.getMessage(StackLineAnalyser.class,
"AnalyzeStackTopComponent.lineNotFound",
new Object[]{lineNumber}));
}
}
try {
EditorCookie editorCookie = dataObject.getLookup().lookup(EditorCookie.class);
LineCookie lineCookie = dataObject.getLookup().lookup(LineCookie.class);
if (editorCookie != null && lineCookie != null && lineNumber != -1) {
StyledDocument doc = editorCookie.openDocument();
if (doc != null) {
if (lineNumber != -1) {
try {
Line l = lineCookie.getLineSet().getCurrent(lineNumber - 1);
if (l != null) {
l.show(Line.ShowOpenType.OPEN, Line.ShowVisibilityType.FRONT);
return;
}
} catch (IndexOutOfBoundsException oob) {
//line number is no more valid, do not report as an error
StatusDisplayer.getDefault().setStatusText(
NbBundle.getMessage(StackLineAnalyser.class,
"AnalyzeStackTopComponent.lineNotFound",
new Object[]{lineNumber}));
}
OpenCookie openCookie = (OpenCookie) dataObject.getCookie(OpenCookie.class);
if (openCookie != null) {
openCookie.open();
return;
}
} catch (IOException e) {
Exceptions.printStackTrace(e);
}
} finally {
handle.finish();
}
}
});
OpenCookie openCookie = dataObject.getLookup().lookup(OpenCookie.class);
if (openCookie != null) {
openCookie.open();
return;
}
} catch (IOException e) {
Exceptions.printStackTrace(e);
}
} finally {
handle.finish();
}
}
});
});
}
});
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,17 +48,40 @@ public void testMatches() throws Exception {
assertTrue(StackLineAnalyser.matches(" [exec] at org.openide.filesystems.FileUtil.normalizeFileOnMac(FileUtil.java:1714)"));
assertTrue(StackLineAnalyser.matches("at java.base/java.lang.String.lastIndexOf(String.java:1627)"));
assertTrue(StackLineAnalyser.matches(" at java.base/java.lang.String.lastIndexOf(String.java:1627)"));
// some loggers (e.g. MavenSimpleLogger until MNG-7970/#1342 which is maven's default logger) seem to add a space before the '('
assertTrue(StackLineAnalyser.matches(" at java.util.zip.ZipFile$CleanableResource.<init> (ZipFile.java:742)"));
}

@Test
public void testMatchesScalaLines() throws Exception {
assertTrue(StackLineAnalyser.matches("at org.enso.compiler.core.ir.MetadataStorage.$anonfun$getUnsafe$1(MetadataStorage.scala:80)"));
StackLineAnalyser.Link l = StackLineAnalyser.analyse("at org.enso.compiler.core.ir.MetadataStorage.$anonfun$getUnsafe$1(MetadataStorage.scala:80)");
String line = "at org.enso.compiler.core.ir.MetadataStorage.$anonfun$getUnsafe$1(MetadataStorage.scala:80)";
assertTrue(StackLineAnalyser.matches(line));
StackLineAnalyser.Link l = StackLineAnalyser.analyse(line);
assertEquals(3, l.getStartOffset());
assertEquals(91, l.getEndOffset());
assertEquals(".scala", l.getExtension());
}

@Test
public void testMatchesUnknownFileLines() throws Exception {
String line = "at org.Unknown(Unknown:80)";
assertTrue(StackLineAnalyser.matches(line));
StackLineAnalyser.Link l = StackLineAnalyser.analyse(line);
assertEquals(3, l.getStartOffset());
assertEquals(26, l.getEndOffset());
assertEquals(null, l.getExtension());
}

@Test
public void testMatchesWithNoPackage() throws Exception {
String line = "\tat NewClass.main(NewClass.java:12)";
assertTrue(StackLineAnalyser.matches(line));
StackLineAnalyser.Link l = StackLineAnalyser.analyse(line);
assertEquals(4, l.getStartOffset());
assertEquals(35, l.getEndOffset());
assertEquals(".java", l.getExtension());
}

@Test
public void testModuleStackTraceMatches() throws Exception {
assertTrue(StackLineAnalyser.matches("at library.Library.init(Utilities/Library.java:24)"));
Expand All @@ -85,6 +108,9 @@ public void testAnalyse() throws Exception {
l = StackLineAnalyser.analyse(" at java.base/java.lang.String.lastIndexOf(String.java:1627)");
assertEquals(4, l.getStartOffset());
assertEquals(60, l.getEndOffset());
l = StackLineAnalyser.analyse(" at java.util.zip.ZipFile$CleanableResource.<init> (ZipFile.java:742)");
assertEquals(7, l.getStartOffset());
assertEquals(72, l.getEndOffset());
}

@Test
Expand Down