From 0bb4f09646fca387a2042e3a320a563515fd9cd5 Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Sat, 28 Nov 2020 23:05:53 +0100 Subject: [PATCH] JavaStackTrace: Added support stack frame element class loaders and modules (#2658) --- components/prism-javastacktrace.js | 54 ++++- components/prism-javastacktrace.min.js | 2 +- .../javastacktrace/stack-frame_feature.test | 201 +++++++++++++++++- 3 files changed, 246 insertions(+), 11 deletions(-) diff --git a/components/prism-javastacktrace.js b/components/prism-javastacktrace.js index 8c1b128ea1..51b4084b96 100644 --- a/components/prism-javastacktrace.js +++ b/components/prism-javastacktrace.js @@ -1,3 +1,6 @@ +// Specification: +// https://docs.oracle.com/en/java/javase/13/docs/api/java.base/java/lang/Throwable.html#printStackTrace() + Prism.languages.javastacktrace = { // java.sql.SQLException: Violation of unique constraint MY_ENTITY_UK_1: duplicate value(s) for column(s) MY_COLUMN in statement [...] @@ -38,12 +41,30 @@ Prism.languages.javastacktrace = { // at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1166) // at org.hsqldb.jdbc.Util.throwError(Unknown Source) here could be some notes + // at java.base/java.lang.Class.forName0(Native Method) // at Util.(Unknown Source) + // at com.foo.loader/foo@9.0/com.foo.Main.run(Main.java:101) + // at com.foo.loader//com.foo.bar.App.run(App.java:12) + // at acme@2.1/org.acme.Lib.test(Lib.java:80) + // at MyClass.mash(MyClass.java:9) + // + // More information: + // https://docs.oracle.com/en/java/javase/13/docs/api/java.base/java/lang/StackTraceElement.html#toString() + // + // A valid Java module name is defined as: + // "A module name consists of one or more Java identifiers (ยง3.8) separated by "." tokens." + // https://docs.oracle.com/javase/specs/jls/se9/html/jls-6.html#jls-ModuleName + // + // A Java module version is defined by this class: + // https://docs.oracle.com/javase/9/docs/api/java/lang/module/ModuleDescriptor.Version.html + // This is the implementation of the `parse` method in JDK13: + // https://github.com/matcdac/jdk/blob/2305df71d1b7710266ae0956d73927a225132c0f/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java#L1108 + // However, to keep this simple, a version will be matched by the pattern /@[\w$.+-]*/. 'stack-frame': { - pattern: /^[\t ]*at [\w$.]+(?:)?\([^()]*\)/m, + pattern: /^[\t ]*at (?:[\w$./]|@[\w$.+-]*\/)+(?:)?\([^()]*\)/m, inside: { 'keyword': { - pattern: /^(\s*)at/, + pattern: /^(\s*)at(?= )/, lookbehind: true }, 'source': [ @@ -74,8 +95,33 @@ Prism.languages.javastacktrace = { ], 'class-name': /[\w$]+(?=\.(?:|[\w$]+)\()/, 'function': /(?:|[\w$]+)(?=\()/, - 'namespace': /[a-z]\w*/, - 'punctuation': /[.()]/ + 'class-loader': { + pattern: /(\s)[a-z]\w*(?:\.[a-z]\w*)*(?=\/[\w@$.]*\/)/, + lookbehind: true, + alias: 'namespace', + inside: { + 'punctuation': /\./ + } + }, + 'module': { + pattern: /([\s/])[a-z]\w*(?:\.[a-z]\w*)*(?:@[\w$.+-]*)?(?=\/)/, + lookbehind: true, + inside: { + 'version': { + pattern: /(@)[\s\S]+/, + lookbehind: true, + alias: 'number' + }, + 'punctuation': /[@.]/ + } + }, + 'namespace': { + pattern: /(?:[a-z]\w*\.)+/, + inside: { + 'punctuation': /\./ + } + }, + 'punctuation': /[()/.]/ } }, diff --git a/components/prism-javastacktrace.min.js b/components/prism-javastacktrace.min.js index fe64b1c2aa..6c731e264b 100644 --- a/components/prism-javastacktrace.min.js +++ b/components/prism-javastacktrace.min.js @@ -1 +1 @@ -Prism.languages.javastacktrace={summary:{pattern:/^[\t ]*(?:(?:Caused by:|Suppressed:|Exception in thread "[^"]*")[\t ]+)?[\w$.]+(?:\:.*)?$/m,inside:{keyword:{pattern:/^(\s*)(?:(?:Caused by|Suppressed)(?=:)|Exception in thread)/m,lookbehind:!0},string:{pattern:/^(\s*)"[^"]*"/,lookbehind:!0},exceptions:{pattern:/^(:?\s*)[\w$.]+(?=:|$)/,lookbehind:!0,inside:{"class-name":/[\w$]+(?=$|:)/,namespace:/[a-z]\w*/,punctuation:/[.:]/}},message:{pattern:/(:\s*)\S.*/,lookbehind:!0,alias:"string"},punctuation:/[:]/}},"stack-frame":{pattern:/^[\t ]*at [\w$.]+(?:)?\([^()]*\)/m,inside:{keyword:{pattern:/^(\s*)at/,lookbehind:!0},source:[{pattern:/(\()\w+.\w+:\d+(?=\))/,lookbehind:!0,inside:{file:/^\w+\.\w+/,punctuation:/:/,"line-number":{pattern:/\d+/,alias:"number"}}},{pattern:/(\()[^()]*(?=\))/,lookbehind:!0,inside:{keyword:/^(?:Unknown Source|Native Method)$/}}],"class-name":/[\w$]+(?=\.(?:|[\w$]+)\()/,function:/(?:|[\w$]+)(?=\()/,namespace:/[a-z]\w*/,punctuation:/[.()]/}},more:{pattern:/^[\t ]*\.{3} \d+ [a-z]+(?: [a-z]+)*/m,inside:{punctuation:/\.{3}/,number:/\d+/,keyword:/\b[a-z]+(?: [a-z]+)*\b/}}}; \ No newline at end of file +Prism.languages.javastacktrace={summary:{pattern:/^[\t ]*(?:(?:Caused by:|Suppressed:|Exception in thread "[^"]*")[\t ]+)?[\w$.]+(?:\:.*)?$/m,inside:{keyword:{pattern:/^(\s*)(?:(?:Caused by|Suppressed)(?=:)|Exception in thread)/m,lookbehind:!0},string:{pattern:/^(\s*)"[^"]*"/,lookbehind:!0},exceptions:{pattern:/^(:?\s*)[\w$.]+(?=:|$)/,lookbehind:!0,inside:{"class-name":/[\w$]+(?=$|:)/,namespace:/[a-z]\w*/,punctuation:/[.:]/}},message:{pattern:/(:\s*)\S.*/,lookbehind:!0,alias:"string"},punctuation:/[:]/}},"stack-frame":{pattern:/^[\t ]*at (?:[\w$./]|@[\w$.+-]*\/)+(?:)?\([^()]*\)/m,inside:{keyword:{pattern:/^(\s*)at(?= )/,lookbehind:!0},source:[{pattern:/(\()\w+.\w+:\d+(?=\))/,lookbehind:!0,inside:{file:/^\w+\.\w+/,punctuation:/:/,"line-number":{pattern:/\d+/,alias:"number"}}},{pattern:/(\()[^()]*(?=\))/,lookbehind:!0,inside:{keyword:/^(?:Unknown Source|Native Method)$/}}],"class-name":/[\w$]+(?=\.(?:|[\w$]+)\()/,function:/(?:|[\w$]+)(?=\()/,"class-loader":{pattern:/(\s)[a-z]\w*(?:\.[a-z]\w*)*(?=\/[\w@$.]*\/)/,lookbehind:!0,alias:"namespace",inside:{punctuation:/\./}},module:{pattern:/([\s/])[a-z]\w*(?:\.[a-z]\w*)*(?:@[\w$.+-]*)?(?=\/)/,lookbehind:!0,inside:{version:{pattern:/(@)[\s\S]+/,lookbehind:!0,alias:"number"},punctuation:/[@.]/}},namespace:{pattern:/(?:[a-z]\w*\.)+/,inside:{punctuation:/\./}},punctuation:/[()/.]/}},more:{pattern:/^[\t ]*\.{3} \d+ [a-z]+(?: [a-z]+)*/m,inside:{punctuation:/\.{3}/,number:/\d+/,keyword:/\b[a-z]+(?: [a-z]+)*\b/}}}; \ No newline at end of file diff --git a/tests/languages/javastacktrace/stack-frame_feature.test b/tests/languages/javastacktrace/stack-frame_feature.test index b4c400e458..3952815467 100644 --- a/tests/languages/javastacktrace/stack-frame_feature.test +++ b/tests/languages/javastacktrace/stack-frame_feature.test @@ -2,6 +2,15 @@ at Main.main(Main.java:13) at Main.main(Main.java:13) Same but with some additional notes at com.foo.bar.Main$FooBar.main(Native Method) at Main$FooBar.(Unknown Source) + at java.base/java.util.jar.JavaUtilJarAccessImpl.ensureInitialization(JavaUtilJarAccessImpl.java:69) + at java.base/java.lang.Class.forName0(Native Method) +at com.foo.loader/foo@9.0/com.foo.Main.run(Main.java:101) +at com.foo.loader//com.foo.bar.App.run(App.java:12) +at acme@2.1/org.acme.Lib.test(Lib.java:80) +at MyClass.mash(MyClass.java:9) + +// not to forget our swiss friends +at at.foo.bar.Main$FooBar.main(Native Method) ---------------------------------------------------- @@ -37,12 +46,14 @@ at Main$FooBar.(Unknown Source) ["stack-frame", [ ["keyword", "at"], - ["namespace", "com"], - ["punctuation", "."], - ["namespace", "foo"], - ["punctuation", "."], - ["namespace", "bar"], - ["punctuation", "."], + ["namespace", [ + "com", + ["punctuation", "."], + "foo", + ["punctuation", "."], + "bar", + ["punctuation", "."] + ]], ["class-name", "Main$FooBar"], ["punctuation", "."], ["function", "main"], @@ -63,6 +74,184 @@ at Main$FooBar.(Unknown Source) ["keyword", "Unknown Source"] ]], ["punctuation", ")"] + ]], + + ["stack-frame", [ + ["keyword", "at"], + ["module", [ + "java", + ["punctuation", "."], + "base" + ]], + ["punctuation", "/"], + ["namespace", [ + "java", + ["punctuation", "."], + "util", + ["punctuation", "."], + "jar", + ["punctuation", "."] + ]], + ["class-name", "JavaUtilJarAccessImpl"], + ["punctuation", "."], + ["function", "ensureInitialization"], + ["punctuation", "("], + ["source", [ + ["file", "JavaUtilJarAccessImpl.java"], + ["punctuation", ":"], + ["line-number", "69"] + ]], + ["punctuation", ")"] + ]], + + ["stack-frame", [ + ["keyword", "at"], + ["module", [ + "java", + ["punctuation", "."], + "base" + ]], + ["punctuation", "/"], + ["namespace", [ + "java", + ["punctuation", "."], + "lang", + ["punctuation", "."] + ]], + ["class-name", "Class"], + ["punctuation", "."], + ["function", "forName0"], + ["punctuation", "("], + ["source", [ + ["keyword", "Native Method"] + ]], + ["punctuation", ")"] + ]], + + ["stack-frame", [ + ["keyword", "at"], + ["class-loader", [ + "com", + ["punctuation", "."], + "foo", + ["punctuation", "."], + "loader" + ]], + ["punctuation", "/"], + ["module", [ + "foo", + ["punctuation", "@"], + ["version", "9.0"] + ]], + ["punctuation", "/"], + ["namespace", [ + "com", + ["punctuation", "."], + "foo", + ["punctuation", "."] + ]], + ["class-name", "Main"], + ["punctuation", "."], + ["function", "run"], + ["punctuation", "("], + ["source", [ + ["file", "Main.java"], + ["punctuation", ":"], + ["line-number", "101"] + ]], + ["punctuation", ")"] + ]], + + ["stack-frame", [ + ["keyword", "at"], + ["class-loader", [ + "com", + ["punctuation", "."], + "foo", + ["punctuation", "."], + "loader" + ]], + ["punctuation", "/"], + ["punctuation", "/"], + ["namespace", [ + "com", + ["punctuation", "."], + "foo", + ["punctuation", "."], + "bar", + ["punctuation", "."] + ]], + ["class-name", "App"], + ["punctuation", "."], + ["function", "run"], + ["punctuation", "("], + ["source", [ + ["file", "App.java"], + ["punctuation", ":"], + ["line-number", "12"] + ]], + ["punctuation", ")"] + ]], + + ["stack-frame", [ + ["keyword", "at"], + ["module", [ + "acme", + ["punctuation", "@"], + ["version", "2.1"] + ]], + ["punctuation", "/"], + ["namespace", [ + "org", + ["punctuation", "."], + "acme", + ["punctuation", "."] + ]], + ["class-name", "Lib"], + ["punctuation", "."], + ["function", "test"], + ["punctuation", "("], + ["source", [ + ["file", "Lib.java"], + ["punctuation", ":"], + ["line-number", "80"] + ]], + ["punctuation", ")"] + ]], + + ["stack-frame", [ + ["keyword", "at"], + ["class-name", "MyClass"], + ["punctuation", "."], + ["function", "mash"], + ["punctuation", "("], + ["source", [ + ["file", "MyClass.java"], + ["punctuation", ":"], + ["line-number", "9"] + ]], + ["punctuation", ")"] + ]], + + "\n\n// not to forget our swiss friends\n", + ["stack-frame", [ + ["keyword", "at"], + ["namespace", [ + "at", + ["punctuation", "."], + "foo", + ["punctuation", "."], + "bar", + ["punctuation", "."] + ]], + ["class-name", "Main$FooBar"], + ["punctuation", "."], + ["function", "main"], + ["punctuation", "("], + ["source", [ + ["keyword", "Native Method"] + ]], + ["punctuation", ")"] ]] ]