mirror of
https://github.com/java-decompiler/jd-gui.git
synced 2024-12-11 14:33:42 +00:00
Adds support for JAVA files
This commit is contained in:
parent
411348dc6b
commit
e8a49c4e75
@ -10,3 +10,59 @@ dependencies {
|
|||||||
compile project(':api')
|
compile project(':api')
|
||||||
testCompile 'org.codehaus.groovy:groovy-test:2.4.0'
|
testCompile 'org.codehaus.groovy:groovy-test:2.4.0'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ANTLR //
|
||||||
|
ext.antlr4 = [
|
||||||
|
antlrSource: 'src/main/antlr',
|
||||||
|
destinationDir: 'src-generated/antlr/java',
|
||||||
|
grammarPackage: 'jd.gui.util.parser.antlr'
|
||||||
|
]
|
||||||
|
|
||||||
|
configurations {
|
||||||
|
antlr4 {
|
||||||
|
description = "ANTLR4"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compile 'org.antlr:antlr4-runtime:4.5'
|
||||||
|
antlr4 'org.antlr:antlr4:4.5'
|
||||||
|
}
|
||||||
|
|
||||||
|
task antlr4OutputDir() {
|
||||||
|
mkdir antlr4.destinationDir
|
||||||
|
}
|
||||||
|
|
||||||
|
task antlr4GenerateGrammarSource(dependsOn: antlr4OutputDir, type: JavaExec) {
|
||||||
|
description = 'Generates Java sources from ANTLR4 grammars.'
|
||||||
|
|
||||||
|
inputs.dir file(antlr4.antlrSource)
|
||||||
|
outputs.dir file(antlr4.destinationDir)
|
||||||
|
|
||||||
|
def grammars = fileTree(antlr4.antlrSource).include('**/*.g4')
|
||||||
|
def pkg = antlr4.grammarPackage.replaceAll("\\.", "/")
|
||||||
|
|
||||||
|
main = 'org.antlr.v4.Tool'
|
||||||
|
classpath = configurations.antlr4
|
||||||
|
args = ['-o', "${antlr4.destinationDir}/${pkg}", '-atn', '-package', antlr4.grammarPackage, grammars.files].flatten()
|
||||||
|
}
|
||||||
|
|
||||||
|
compileJava {
|
||||||
|
dependsOn antlr4GenerateGrammarSource
|
||||||
|
source antlr4.destinationDir
|
||||||
|
}
|
||||||
|
|
||||||
|
clean {
|
||||||
|
delete 'src-generated'
|
||||||
|
}
|
||||||
|
|
||||||
|
idea.module {
|
||||||
|
sourceDirs += file(antlr4.destinationDir)
|
||||||
|
}
|
||||||
|
ideaModule.dependsOn antlr4GenerateGrammarSource
|
||||||
|
|
||||||
|
eclipse.classpath.file.withXml { xml ->
|
||||||
|
def node = xml.asNode()
|
||||||
|
node.appendNode( 'classpathentry', [ kind: 'src', path: antlr4.destinationDir])
|
||||||
|
}
|
||||||
|
eclipseClasspath.dependsOn antlr4GenerateGrammarSource
|
||||||
|
1020
services/src/main/antlr/Java.g4
Normal file
1020
services/src/main/antlr/Java.g4
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2008-2015 Emmanuel Dupuy
|
||||||
|
* This program is made available under the terms of the GPLv3 License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package jd.gui.service.fileloader
|
||||||
|
|
||||||
|
import jd.gui.api.API
|
||||||
|
import jd.gui.api.feature.UriOpenable
|
||||||
|
|
||||||
|
import java.nio.file.Paths
|
||||||
|
|
||||||
|
abstract class AbstractTypeFileLoaderProvider extends AbstractFileLoaderProvider {
|
||||||
|
|
||||||
|
protected boolean load(API api, File file, String pathInFile) {
|
||||||
|
// Search root path
|
||||||
|
String pathSuffix = pathInFile
|
||||||
|
String path = file.path
|
||||||
|
|
||||||
|
while (! path.endsWith(pathSuffix)) {
|
||||||
|
int index = pathSuffix.indexOf(File.separator)
|
||||||
|
|
||||||
|
if (index == -1) {
|
||||||
|
pathSuffix = ''
|
||||||
|
} else {
|
||||||
|
pathSuffix = pathSuffix.substring(index+1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pathSuffix) {
|
||||||
|
// Init root file
|
||||||
|
File rootFile = file
|
||||||
|
int index = pathSuffix.indexOf(File.separator)
|
||||||
|
|
||||||
|
while (index != -1) {
|
||||||
|
rootFile = rootFile.parentFile
|
||||||
|
pathSuffix = pathSuffix.substring(index+1)
|
||||||
|
index = pathSuffix.indexOf(File.separator)
|
||||||
|
}
|
||||||
|
rootFile = rootFile.parentFile
|
||||||
|
|
||||||
|
// Create panel
|
||||||
|
def mainPanel = load(api, rootFile, Paths.get(rootFile.toURI()))
|
||||||
|
|
||||||
|
if (mainPanel instanceof UriOpenable) {
|
||||||
|
// Open page
|
||||||
|
pathSuffix = file.absolutePath.substring(rootFile.absolutePath.length()).replace(File.separator, '/')
|
||||||
|
def rootUri = rootFile.toURI()
|
||||||
|
def uri = new URI(rootUri.scheme, rootUri.host, rootUri.path + '!' + pathSuffix, null)
|
||||||
|
mainPanel.openUri(uri)
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return mainPanel != null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -7,11 +7,8 @@ package jd.gui.service.fileloader
|
|||||||
|
|
||||||
import groovyjarjarasm.asm.ClassReader
|
import groovyjarjarasm.asm.ClassReader
|
||||||
import jd.gui.api.API
|
import jd.gui.api.API
|
||||||
import jd.gui.api.feature.UriOpenable
|
|
||||||
|
|
||||||
import java.nio.file.Paths
|
class ClassFileLoaderProvider extends AbstractTypeFileLoaderProvider {
|
||||||
|
|
||||||
class ClassFileLoaderProvider extends AbstractFileLoaderProvider {
|
|
||||||
|
|
||||||
String[] getExtensions() { ['class'] }
|
String[] getExtensions() { ['class'] }
|
||||||
String getDescription() { 'Class files (*.class)' }
|
String getDescription() { 'Class files (*.class)' }
|
||||||
@ -22,48 +19,10 @@ class ClassFileLoaderProvider extends AbstractFileLoaderProvider {
|
|||||||
|
|
||||||
boolean load(API api, File file) {
|
boolean load(API api, File file) {
|
||||||
file.withInputStream { is ->
|
file.withInputStream { is ->
|
||||||
ClassReader classReader = new ClassReader(is)
|
def classReader = new ClassReader(is)
|
||||||
|
def pathInFile = classReader.className.replace('/', File.separator) + '.class'
|
||||||
|
|
||||||
// Search root path
|
return load(api, file, pathInFile)
|
||||||
def pathSuffix = classReader.className.replace('/', File.separator) + '.class'
|
|
||||||
def path = file.path
|
|
||||||
|
|
||||||
while (! path.endsWith(pathSuffix)) {
|
|
||||||
int index = pathSuffix.indexOf(File.separator)
|
|
||||||
|
|
||||||
if (index == -1) {
|
|
||||||
pathSuffix = ''
|
|
||||||
} else {
|
|
||||||
pathSuffix = pathSuffix.substring(index+1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pathSuffix) {
|
|
||||||
// Init root file
|
|
||||||
File rootFile = file
|
|
||||||
int index = pathSuffix.indexOf(File.separator)
|
|
||||||
|
|
||||||
while (index != -1) {
|
|
||||||
rootFile = rootFile.parentFile
|
|
||||||
pathSuffix = pathSuffix.substring(index+1)
|
|
||||||
index = pathSuffix.indexOf(File.separator)
|
|
||||||
}
|
|
||||||
rootFile = rootFile.parentFile
|
|
||||||
|
|
||||||
// Create panel
|
|
||||||
def mainPanel = load(api, rootFile, Paths.get(rootFile.toURI()))
|
|
||||||
|
|
||||||
if (mainPanel instanceof UriOpenable) {
|
|
||||||
// Open page
|
|
||||||
pathSuffix = file.absolutePath.substring(rootFile.absolutePath.length()).replace(File.separator, '/')
|
|
||||||
def rootUri = rootFile.toURI()
|
|
||||||
def uri = new URI(rootUri.scheme, rootUri.host, rootUri.path + '!' + pathSuffix, null)
|
|
||||||
mainPanel.openUri(uri)
|
|
||||||
return true
|
|
||||||
} else {
|
|
||||||
return mainPanel != null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2008-2015 Emmanuel Dupuy
|
||||||
|
* This program is made available under the terms of the GPLv3 License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package jd.gui.service.fileloader
|
||||||
|
|
||||||
|
import jd.gui.api.API
|
||||||
|
|
||||||
|
import java.util.regex.Pattern
|
||||||
|
|
||||||
|
class JavaFileLoaderProvider extends AbstractTypeFileLoaderProvider {
|
||||||
|
|
||||||
|
String[] getExtensions() { ['java'] }
|
||||||
|
String getDescription() { 'Java files (*.java)' }
|
||||||
|
|
||||||
|
boolean accept(API api, File file) {
|
||||||
|
return file.exists() && file.canRead() && file.name.toLowerCase().endsWith('.java')
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean load(API api, File file) {
|
||||||
|
def pattern = Pattern.compile('(?s)(.*\\s)?package\\s+(\\S+)\\s*;.*')
|
||||||
|
def matcher = file.text =~ pattern
|
||||||
|
|
||||||
|
if (matcher.matches()) {
|
||||||
|
// Package name found
|
||||||
|
def pathInFile = matcher[0][2].replace('.', File.separator) + File.separator + file.name
|
||||||
|
|
||||||
|
return load(api, file, pathInFile)
|
||||||
|
} else {
|
||||||
|
// Package name not found
|
||||||
|
return load(api, file, file.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -5,7 +5,6 @@
|
|||||||
|
|
||||||
package jd.gui.service.treenode
|
package jd.gui.service.treenode
|
||||||
|
|
||||||
import groovy.transform.CompileStatic
|
|
||||||
import jd.gui.api.API
|
import jd.gui.api.API
|
||||||
import jd.gui.api.feature.PageCreator
|
import jd.gui.api.feature.PageCreator
|
||||||
import jd.gui.api.feature.TreeNodeExpandable
|
import jd.gui.api.feature.TreeNodeExpandable
|
||||||
@ -21,13 +20,13 @@ abstract class AbstractTypeFileTreeNodeFactoryProvider extends AbstractTreeNodeF
|
|||||||
|
|
||||||
static class BaseTreeNode extends DefaultMutableTreeNode implements UriGettable, PageCreator {
|
static class BaseTreeNode extends DefaultMutableTreeNode implements UriGettable, PageCreator {
|
||||||
Container.Entry entry
|
Container.Entry entry
|
||||||
PageFactory pageFactory;
|
PageAndTipFactory factory;
|
||||||
URI uri
|
URI uri
|
||||||
|
|
||||||
BaseTreeNode(Container.Entry entry, String fragment, Object userObject, PageFactory pageFactory) {
|
BaseTreeNode(Container.Entry entry, String fragment, Object userObject, PageAndTipFactory factory) {
|
||||||
super(userObject)
|
super(userObject)
|
||||||
this.entry = entry
|
this.entry = entry
|
||||||
this.pageFactory = pageFactory
|
this.factory = factory
|
||||||
|
|
||||||
if (fragment) {
|
if (fragment) {
|
||||||
def uri = entry.uri
|
def uri = entry.uri
|
||||||
@ -43,50 +42,20 @@ abstract class AbstractTypeFileTreeNodeFactoryProvider extends AbstractTreeNodeF
|
|||||||
// --- PageCreator --- //
|
// --- PageCreator --- //
|
||||||
public <T extends JComponent & UriGettable> T createPage(API api) {
|
public <T extends JComponent & UriGettable> T createPage(API api) {
|
||||||
// Lazy 'tip' initialization
|
// Lazy 'tip' initialization
|
||||||
def file = new File(entry.container.root.uri)
|
userObject.tip = factory.makeTip(api, entry)
|
||||||
def tip = "<html>Location: $file.path"
|
return factory.makePage(api, entry)
|
||||||
|
|
||||||
entry.inputStream.withStream { is ->
|
|
||||||
is.skip(4) // Skip magic number
|
|
||||||
int minorVersion = readUnsignedShort(is)
|
|
||||||
int majorVersion = readUnsignedShort(is)
|
|
||||||
|
|
||||||
if (majorVersion >= 49) {
|
|
||||||
tip += "<br>Java compiler version: ${majorVersion - (49-5)} ($majorVersion.$minorVersion)"
|
|
||||||
} else if (majorVersion >= 45) {
|
|
||||||
tip += "<br>Java compiler version: 1.${majorVersion - (45-1)} ($majorVersion.$minorVersion)"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tip += "</html>"
|
|
||||||
|
|
||||||
userObject.tip = tip
|
|
||||||
|
|
||||||
return pageFactory.make(api, entry)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see java.io.DataInputStream#readUnsignedShort()
|
|
||||||
*/
|
|
||||||
@CompileStatic
|
|
||||||
int readUnsignedShort(InputStream is) throws IOException {
|
|
||||||
int ch1 = is.read()
|
|
||||||
int ch2 = is.read()
|
|
||||||
if ((ch1 | ch2) < 0)
|
|
||||||
throw new EOFException()
|
|
||||||
return (ch1 << 8) + (ch2 << 0)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static class FileTreeNode extends BaseTreeNode implements TreeNodeExpandable {
|
static class FileTreeNode extends BaseTreeNode implements TreeNodeExpandable {
|
||||||
boolean initialized
|
boolean initialized
|
||||||
|
|
||||||
FileTreeNode(Container.Entry entry, Object userObject, PageFactory pageFactory) {
|
FileTreeNode(Container.Entry entry, Object userObject, PageAndTipFactory pageAndTipFactory) {
|
||||||
this(entry, null, userObject, pageFactory)
|
this(entry, null, userObject, pageAndTipFactory)
|
||||||
}
|
}
|
||||||
|
|
||||||
FileTreeNode(Container.Entry entry, String fragment, Object userObject, PageFactory pageFactory) {
|
FileTreeNode(Container.Entry entry, String fragment, Object userObject, PageAndTipFactory factory) {
|
||||||
super(entry, fragment, userObject, pageFactory)
|
super(entry, fragment, userObject, factory)
|
||||||
initialized = false
|
initialized = false
|
||||||
// Add dummy node
|
// Add dummy node
|
||||||
add(new DefaultMutableTreeNode())
|
add(new DefaultMutableTreeNode())
|
||||||
@ -97,9 +66,10 @@ abstract class AbstractTypeFileTreeNodeFactoryProvider extends AbstractTreeNodeF
|
|||||||
if (!initialized) {
|
if (!initialized) {
|
||||||
removeAllChildren()
|
removeAllChildren()
|
||||||
// Create type node
|
// Create type node
|
||||||
def type = api.getTypeFactory(entry)?.make(api, entry, null)
|
def types = api.getTypeFactory(entry)?.make(api, entry)
|
||||||
if (type) {
|
|
||||||
add(new TypeTreeNode(entry, type, new TreeNodeBean(label: type.displayTypeName, icon: type.icon), pageFactory))
|
for (def type : types) {
|
||||||
|
add(new TypeTreeNode(entry, type, new TreeNodeBean(label: type.displayTypeName, icon: type.icon), factory))
|
||||||
}
|
}
|
||||||
|
|
||||||
initialized = true
|
initialized = true
|
||||||
@ -111,8 +81,8 @@ abstract class AbstractTypeFileTreeNodeFactoryProvider extends AbstractTreeNodeF
|
|||||||
boolean initialized
|
boolean initialized
|
||||||
Type type
|
Type type
|
||||||
|
|
||||||
TypeTreeNode(Container.Entry entry, Type type, Object userObject, PageFactory pageFactory) {
|
TypeTreeNode(Container.Entry entry, Type type, Object userObject, PageAndTipFactory factory) {
|
||||||
super(entry, type.name, userObject, pageFactory)
|
super(entry, type.name, userObject, factory)
|
||||||
this.initialized = false
|
this.initialized = false
|
||||||
this.type = type
|
this.type = type
|
||||||
// Add dummy node
|
// Add dummy node
|
||||||
@ -134,7 +104,7 @@ abstract class AbstractTypeFileTreeNodeFactoryProvider extends AbstractTreeNodeF
|
|||||||
type.innerTypes.sort { t1, t2 ->
|
type.innerTypes.sort { t1, t2 ->
|
||||||
t1.name.compareTo(t2.name)
|
t1.name.compareTo(t2.name)
|
||||||
}.each {
|
}.each {
|
||||||
add(new TypeTreeNode(entry, it, new TreeNodeBean(label: it.displayInnerTypeName, icon: it.icon), pageFactory))
|
add(new TypeTreeNode(entry, it, new TreeNodeBean(label: it.displayInnerTypeName, icon: it.icon), factory))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create fields
|
// Create fields
|
||||||
@ -148,7 +118,7 @@ abstract class AbstractTypeFileTreeNodeFactoryProvider extends AbstractTreeNodeF
|
|||||||
}.sort { f1, f2 ->
|
}.sort { f1, f2 ->
|
||||||
f1.label.compareTo(f2.label)
|
f1.label.compareTo(f2.label)
|
||||||
}.each {
|
}.each {
|
||||||
add(new FieldOrMethodTreeNode(entry, it.fragment, new TreeNodeBean(label: it.label, icon: it.icon), pageFactory))
|
add(new FieldOrMethodTreeNode(entry, it.fragment, new TreeNodeBean(label: it.label, icon: it.icon), factory))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create methods
|
// Create methods
|
||||||
@ -161,7 +131,7 @@ abstract class AbstractTypeFileTreeNodeFactoryProvider extends AbstractTreeNodeF
|
|||||||
}.sort { m1, m2 ->
|
}.sort { m1, m2 ->
|
||||||
m1.label.compareTo(m2.label)
|
m1.label.compareTo(m2.label)
|
||||||
}.each {
|
}.each {
|
||||||
add(new FieldOrMethodTreeNode(entry, it.fragment, new TreeNodeBean(label: it.label, icon: it.icon), pageFactory))
|
add(new FieldOrMethodTreeNode(entry, it.fragment, new TreeNodeBean(label: it.label, icon: it.icon), factory))
|
||||||
}
|
}
|
||||||
|
|
||||||
initialized = true
|
initialized = true
|
||||||
@ -400,8 +370,8 @@ abstract class AbstractTypeFileTreeNodeFactoryProvider extends AbstractTreeNodeF
|
|||||||
}
|
}
|
||||||
|
|
||||||
static class FieldOrMethodTreeNode extends BaseTreeNode {
|
static class FieldOrMethodTreeNode extends BaseTreeNode {
|
||||||
FieldOrMethodTreeNode(Container.Entry entry, String fragment, Object userObject, PageFactory pageFactory) {
|
FieldOrMethodTreeNode(Container.Entry entry, String fragment, Object userObject, PageAndTipFactory factory) {
|
||||||
super(entry, fragment, userObject, pageFactory)
|
super(entry, fragment, userObject, factory)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -409,8 +379,9 @@ abstract class AbstractTypeFileTreeNodeFactoryProvider extends AbstractTreeNodeF
|
|||||||
String fragment, label
|
String fragment, label
|
||||||
Icon icon
|
Icon icon
|
||||||
}
|
}
|
||||||
|
|
||||||
interface PageFactory {
|
interface PageAndTipFactory {
|
||||||
public <T extends JComponent & UriGettable> T make(API api, Container.Entry entry);
|
public <T extends JComponent & UriGettable> T makePage(API api, Container.Entry entry);
|
||||||
|
public String makeTip(API api, Container.Entry entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
package jd.gui.service.treenode
|
package jd.gui.service.treenode
|
||||||
|
|
||||||
|
import groovy.transform.CompileStatic
|
||||||
import jd.gui.api.API
|
import jd.gui.api.API
|
||||||
import jd.gui.api.feature.UriGettable
|
import jd.gui.api.feature.UriGettable
|
||||||
import jd.gui.api.model.Container
|
import jd.gui.api.model.Container
|
||||||
@ -17,6 +18,8 @@ import javax.swing.tree.DefaultMutableTreeNode
|
|||||||
class ClassFileTreeNodeFactoryProvider extends AbstractTypeFileTreeNodeFactoryProvider {
|
class ClassFileTreeNodeFactoryProvider extends AbstractTypeFileTreeNodeFactoryProvider {
|
||||||
static final ImageIcon CLASS_FILE_ICON = new ImageIcon(ClassFileTreeNodeFactoryProvider.class.classLoader.getResource('images/classf_obj.png'))
|
static final ImageIcon CLASS_FILE_ICON = new ImageIcon(ClassFileTreeNodeFactoryProvider.class.classLoader.getResource('images/classf_obj.png'))
|
||||||
|
|
||||||
|
static final Factory FACTORY = new Factory();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
// Early class loading
|
// Early class loading
|
||||||
try {
|
try {
|
||||||
@ -36,9 +39,46 @@ class ClassFileTreeNodeFactoryProvider extends AbstractTypeFileTreeNodeFactoryPr
|
|||||||
return new FileTreeNode(
|
return new FileTreeNode(
|
||||||
entry,
|
entry,
|
||||||
new TreeNodeBean(label:name, icon:CLASS_FILE_ICON),
|
new TreeNodeBean(label:name, icon:CLASS_FILE_ICON),
|
||||||
new AbstractTypeFileTreeNodeFactoryProvider.PageFactory() {
|
FACTORY
|
||||||
public <T extends JComponent & UriGettable> T make(API a, Container.Entry e) { new ClassFilePage(a, e) }
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class Factory implements AbstractTypeFileTreeNodeFactoryProvider.PageAndTipFactory {
|
||||||
|
public <T extends JComponent & UriGettable> T makePage(API a, Container.Entry e) {
|
||||||
|
return new ClassFilePage(a, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
public String makeTip(API api, Container.Entry entry) {
|
||||||
|
def file = new File(entry.container.root.uri)
|
||||||
|
def tip = "<html>Location: $file.path"
|
||||||
|
|
||||||
|
entry.inputStream.withStream { is ->
|
||||||
|
is.skip(4) // Skip magic number
|
||||||
|
int minorVersion = readUnsignedShort(is)
|
||||||
|
int majorVersion = readUnsignedShort(is)
|
||||||
|
|
||||||
|
if (majorVersion >= 49) {
|
||||||
|
tip += "<br>Java compiler version: ${majorVersion - (49-5)} ($majorVersion.$minorVersion)"
|
||||||
|
} else if (majorVersion >= 45) {
|
||||||
|
tip += "<br>Java compiler version: 1.${majorVersion - (45-1)} ($majorVersion.$minorVersion)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tip += "</html>"
|
||||||
|
|
||||||
|
return tip
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see java.io.DataInputStream#readUnsignedShort()
|
||||||
|
*/
|
||||||
|
@CompileStatic
|
||||||
|
int readUnsignedShort(InputStream is) throws IOException {
|
||||||
|
int ch1 = is.read()
|
||||||
|
int ch2 = is.read()
|
||||||
|
if ((ch1 | ch2) < 0)
|
||||||
|
throw new EOFException()
|
||||||
|
return (ch1 << 8) + (ch2 << 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2008-2015 Emmanuel Dupuy
|
||||||
|
* This program is made available under the terms of the GPLv3 License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package jd.gui.service.treenode
|
||||||
|
|
||||||
|
import jd.gui.api.API
|
||||||
|
import jd.gui.api.feature.UriGettable
|
||||||
|
import jd.gui.api.model.Container
|
||||||
|
import jd.gui.view.component.JavaFilePage
|
||||||
|
import jd.gui.view.data.TreeNodeBean
|
||||||
|
|
||||||
|
import javax.swing.*
|
||||||
|
import javax.swing.tree.DefaultMutableTreeNode
|
||||||
|
|
||||||
|
class JavaFileTreeNodeFactoryProvider extends AbstractTypeFileTreeNodeFactoryProvider {
|
||||||
|
static final ImageIcon JAVA_FILE_ICON = new ImageIcon(JavaFileTreeNodeFactoryProvider.class.classLoader.getResource('images/jcu_obj.png'))
|
||||||
|
|
||||||
|
static final Factory FACTORY = new Factory();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return local + optional external selectors
|
||||||
|
*/
|
||||||
|
String[] getSelectors() { ['*:file:*.java'] + externalSelectors }
|
||||||
|
|
||||||
|
public <T extends DefaultMutableTreeNode & UriGettable> T make(API api, Container.Entry entry) {
|
||||||
|
int lastSlashIndex = entry.path.lastIndexOf('/')
|
||||||
|
def name = entry.path.substring(lastSlashIndex+1)
|
||||||
|
|
||||||
|
return new FileTreeNode(
|
||||||
|
entry,
|
||||||
|
new TreeNodeBean(label:name, icon:JAVA_FILE_ICON),
|
||||||
|
FACTORY
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Factory implements AbstractTypeFileTreeNodeFactoryProvider.PageAndTipFactory {
|
||||||
|
public <T extends JComponent & UriGettable> T makePage(API a, Container.Entry e) {
|
||||||
|
return new JavaFilePage(a, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
public String makeTip(API api, Container.Entry entry) {
|
||||||
|
def file = new File(entry.container.root.uri)
|
||||||
|
return "<html>Location: $file.path</html>"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -13,22 +13,16 @@ import jd.core.process.DecompilerImpl
|
|||||||
import jd.gui.api.API
|
import jd.gui.api.API
|
||||||
import jd.gui.api.feature.*
|
import jd.gui.api.feature.*
|
||||||
import jd.gui.api.model.Container
|
import jd.gui.api.model.Container
|
||||||
import jd.gui.api.model.Indexes
|
|
||||||
import jd.gui.util.decompiler.ClassFileSourcePrinter
|
import jd.gui.util.decompiler.ClassFileSourcePrinter
|
||||||
import jd.gui.util.decompiler.ContainerLoader
|
import jd.gui.util.decompiler.ContainerLoader
|
||||||
import jd.gui.util.decompiler.GuiPreferences
|
import jd.gui.util.decompiler.GuiPreferences
|
||||||
import jd.gui.util.matcher.DescriptorMatcher
|
|
||||||
import org.fife.ui.rsyntaxtextarea.DocumentRange
|
import org.fife.ui.rsyntaxtextarea.DocumentRange
|
||||||
import org.fife.ui.rsyntaxtextarea.SyntaxConstants
|
import org.fife.ui.rsyntaxtextarea.SyntaxConstants
|
||||||
|
|
||||||
import javax.swing.text.DefaultCaret
|
import javax.swing.text.DefaultCaret
|
||||||
import java.awt.Color
|
import java.awt.Color
|
||||||
import java.awt.Point
|
|
||||||
import java.util.regex.Pattern
|
|
||||||
|
|
||||||
class ClassFilePage
|
class ClassFilePage extends TypePage implements PreferencesChangeListener {
|
||||||
extends CustomLineNumbersPage
|
|
||||||
implements UriGettable, IndexesChangeListener, LineNumberNavigable, FocusedTypeGettable, PreferencesChangeListener {
|
|
||||||
|
|
||||||
protected static final String ESCAPE_UNICODE_CHARACTERS = 'ClassFileViewerPreferences.escapeUnicodeCharacters'
|
protected static final String ESCAPE_UNICODE_CHARACTERS = 'ClassFileViewerPreferences.escapeUnicodeCharacters'
|
||||||
protected static final String OMIT_THIS_PREFIX = 'ClassFileViewerPreferences.omitThisPrefix'
|
protected static final String OMIT_THIS_PREFIX = 'ClassFileViewerPreferences.omitThisPrefix'
|
||||||
@ -37,15 +31,6 @@ class ClassFilePage
|
|||||||
|
|
||||||
protected static final Decompiler DECOMPILER = new DecompilerImpl()
|
protected static final Decompiler DECOMPILER = new DecompilerImpl()
|
||||||
|
|
||||||
protected API api
|
|
||||||
protected Container.Entry entry
|
|
||||||
protected Collection<Indexes> collectionOfIndexes
|
|
||||||
|
|
||||||
protected ArrayList<ReferenceData> references = new ArrayList<>()
|
|
||||||
protected HashMap<String, DeclarationData> declarations = new HashMap<>()
|
|
||||||
protected TreeMap<Integer, DeclarationData> typeDeclarations = new TreeMap<>()
|
|
||||||
protected ArrayList<StringData> strings = new ArrayList<>()
|
|
||||||
|
|
||||||
protected int maximumLineNumber = -1
|
protected int maximumLineNumber = -1
|
||||||
|
|
||||||
static {
|
static {
|
||||||
@ -69,9 +54,7 @@ class ClassFilePage
|
|||||||
}
|
}
|
||||||
|
|
||||||
ClassFilePage(API api, Container.Entry entry) {
|
ClassFilePage(API api, Container.Entry entry) {
|
||||||
// Init attributes
|
super(api, entry)
|
||||||
this.api = api
|
|
||||||
this.entry = entry
|
|
||||||
// Init view
|
// Init view
|
||||||
errorForeground = Color.decode(api.preferences.get('JdGuiPreferences.errorBackgroundColor'))
|
errorForeground = Color.decode(api.preferences.get('JdGuiPreferences.errorBackgroundColor'))
|
||||||
// Display source
|
// Display source
|
||||||
@ -111,43 +94,18 @@ class ClassFilePage
|
|||||||
maximumLineNumber = getMaximumSourceLineNumber()
|
maximumLineNumber = getMaximumSourceLineNumber()
|
||||||
}
|
}
|
||||||
|
|
||||||
String getSyntaxStyle() { SyntaxConstants.SYNTAX_STYLE_JAVA }
|
@CompileStatic
|
||||||
|
protected static boolean getPreferenceValue(Map<String, String> preferences, String key, boolean defaultValue) {
|
||||||
|
String v = preferences.get(key);
|
||||||
|
|
||||||
protected boolean isHyperlinkEnabled(HyperlinkPage.HyperlinkData hyperlinkData) { hyperlinkData.reference.enabled }
|
if (v == null) {
|
||||||
|
return defaultValue;
|
||||||
protected void openHyperlink(int x, int y, HyperlinkPage.HyperlinkData hyperlinkData) {
|
} else {
|
||||||
if (hyperlinkData.reference.enabled) {
|
return Boolean.valueOf(v);
|
||||||
// Save current position in history
|
|
||||||
def location = textArea.getLocationOnScreen()
|
|
||||||
int offset = textArea.viewToModel(new Point(x-location.x as int, y-location.y as int))
|
|
||||||
def uri = entry.uri
|
|
||||||
api.addURI(new URI(uri.scheme, uri.authority, uri.path, 'position=' + offset, null))
|
|
||||||
|
|
||||||
// Open link
|
|
||||||
def reference = hyperlinkData.reference
|
|
||||||
def typeName = reference.type
|
|
||||||
def entries = collectionOfIndexes?.collect { it.getIndex('typeDeclarations')?.get(typeName) }.flatten().grep { it!=null }
|
|
||||||
def rootUri = entry.container.root.uri.toString()
|
|
||||||
def sameContainerEntries = entries?.grep { it.uri.toString().startsWith(rootUri) }
|
|
||||||
def fragment = typeName
|
|
||||||
|
|
||||||
if (reference.name) {
|
|
||||||
fragment += '-' + reference.name
|
|
||||||
}
|
|
||||||
if (reference.descriptor) {
|
|
||||||
fragment += '-' + reference.descriptor
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sameContainerEntries) {
|
|
||||||
api.openURI(x, y, sameContainerEntries, null, fragment)
|
|
||||||
} else if (entries) {
|
|
||||||
api.openURI(x, y, entries, null, fragment)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- UriGettable --- //
|
String getSyntaxStyle() { SyntaxConstants.SYNTAX_STYLE_JAVA }
|
||||||
URI getUri() { entry.uri }
|
|
||||||
|
|
||||||
// --- ContentSavable --- //
|
// --- ContentSavable --- //
|
||||||
String getFileName() {
|
String getFileName() {
|
||||||
@ -156,89 +114,6 @@ class ClassFilePage
|
|||||||
return path.substring(0, index) + '.java'
|
return path.substring(0, index) + '.java'
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- IndexesChangeListener --- //
|
|
||||||
@CompileStatic
|
|
||||||
void indexesChanged(Collection<Indexes> collectionOfIndexes) {
|
|
||||||
// Update the list of containers
|
|
||||||
this.collectionOfIndexes = collectionOfIndexes
|
|
||||||
// Refresh links
|
|
||||||
boolean refresh = false
|
|
||||||
|
|
||||||
for (def reference : references) {
|
|
||||||
def typeName = reference.type
|
|
||||||
boolean enabled
|
|
||||||
|
|
||||||
if (reference.name) {
|
|
||||||
typeName = searchTypeHavingMember(typeName, reference.name, reference.descriptor, entry)
|
|
||||||
if (typeName) {
|
|
||||||
// Replace type with the real type containing the referenced member
|
|
||||||
reference.type = typeName
|
|
||||||
enabled = true
|
|
||||||
} else {
|
|
||||||
enabled = false
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
enabled = collectionOfIndexes.find { it.getIndex('typeDeclarations')?.get(typeName) } != null
|
|
||||||
}
|
|
||||||
|
|
||||||
if (reference.enabled != enabled) {
|
|
||||||
reference.enabled = enabled
|
|
||||||
refresh = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (refresh) {
|
|
||||||
textArea.repaint()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String searchTypeHavingMember(String typeName, String name, String descriptor, Container.Entry entry) {
|
|
||||||
def entries = collectionOfIndexes?.collect { it.getIndex('typeDeclarations')?.get(typeName) }.flatten().grep { it!=null }
|
|
||||||
def rootUri = entry.container.root.uri.toString()
|
|
||||||
def sameContainerEntries = entries?.grep { Container.Entry e -> e.uri.toString().startsWith(rootUri) }
|
|
||||||
|
|
||||||
if (sameContainerEntries) {
|
|
||||||
return searchTypeHavingMember(typeName, name, descriptor, sameContainerEntries)
|
|
||||||
} else {
|
|
||||||
return searchTypeHavingMember(typeName, name, descriptor, entries)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@CompileStatic
|
|
||||||
protected String searchTypeHavingMember(String typeName, String name, String descriptor, List<Container.Entry> entries) {
|
|
||||||
for (def entry : entries) {
|
|
||||||
def type = api.getTypeFactory(entry).make(api, entry, null)
|
|
||||||
|
|
||||||
if (type) {
|
|
||||||
if (descriptor.indexOf('(') == -1) {
|
|
||||||
// Search a field
|
|
||||||
for (def field : type.fields) {
|
|
||||||
if (field.name.equals(name) && field.descriptor.equals(descriptor)) {
|
|
||||||
// Field found
|
|
||||||
return typeName
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Search a method
|
|
||||||
for (def method : type.methods) {
|
|
||||||
if (method.name.equals(name) && method.descriptor.equals(descriptor)) {
|
|
||||||
// Method found
|
|
||||||
return typeName
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Not found -> Search in super type
|
|
||||||
def typeOwnerName = searchTypeHavingMember(type.superName, name, descriptor, entry)
|
|
||||||
if (typeOwnerName) {
|
|
||||||
return typeOwnerName
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- LineNumberNavigable --- //
|
// --- LineNumberNavigable --- //
|
||||||
int getMaximumLineNumber() { maximumLineNumber }
|
int getMaximumLineNumber() { maximumLineNumber }
|
||||||
|
|
||||||
@ -253,218 +128,6 @@ class ClassFilePage
|
|||||||
|
|
||||||
boolean checkLineNumber(int lineNumber) { lineNumber <= maximumLineNumber }
|
boolean checkLineNumber(int lineNumber) { lineNumber <= maximumLineNumber }
|
||||||
|
|
||||||
// --- UriOpenable --- //
|
|
||||||
/**
|
|
||||||
* @param uri for URI format, @see jd.gui.api.feature.UriOpenable
|
|
||||||
*/
|
|
||||||
boolean openUri(URI uri) {
|
|
||||||
List<DocumentRange> ranges = []
|
|
||||||
def fragment = uri.fragment
|
|
||||||
def query = uri.query
|
|
||||||
|
|
||||||
textArea.highlighter.clearMarkAllHighlights()
|
|
||||||
|
|
||||||
if (fragment) {
|
|
||||||
matchFragmentAndAddDocumentRange(fragment, declarations, ranges)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (query) {
|
|
||||||
Map<String, String> parameters = parseQuery(query)
|
|
||||||
|
|
||||||
if (parameters.containsKey('lineNumber')) {
|
|
||||||
def lineNumber = parameters.get('lineNumber')
|
|
||||||
if (lineNumber.isNumber()) {
|
|
||||||
goToLineNumber(lineNumber.toInteger())
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
} else if (parameters.containsKey('position')) {
|
|
||||||
def position = parameters.get('position')
|
|
||||||
if (position.isNumber()) {
|
|
||||||
int pos = position.toInteger()
|
|
||||||
if (textArea.document.length > pos) {
|
|
||||||
ranges.add(new DocumentRange(pos, pos))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
matchQueryAndAddDocumentRange(parameters, declarations, hyperlinks, strings, ranges)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ranges) {
|
|
||||||
textArea.markAllHighlightColor = SELECT_HIGHLIGHT_COLOR
|
|
||||||
textArea.markAll(ranges)
|
|
||||||
setCaretPositionAndCenter(ranges.sort().get(0))
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
@CompileStatic
|
|
||||||
static void matchFragmentAndAddDocumentRange(
|
|
||||||
String fragment, HashMap<String, DeclarationData> declarations, List<DocumentRange> ranges) {
|
|
||||||
|
|
||||||
if ((fragment.indexOf('?') != -1) || (fragment.indexOf('*') != -1)) {
|
|
||||||
// Unknown type and/or descriptor ==> Select all and scroll to the first one
|
|
||||||
int lastDash = fragment.lastIndexOf('-')
|
|
||||||
|
|
||||||
if (lastDash == -1) {
|
|
||||||
// Search types
|
|
||||||
String slashAndTypeName = fragment.substring(1)
|
|
||||||
String typeName = fragment.substring(2)
|
|
||||||
|
|
||||||
for (def entry : declarations.entrySet()) {
|
|
||||||
if (entry.key.endsWith(slashAndTypeName) || entry.key.equals(typeName)) {
|
|
||||||
ranges.add(new DocumentRange(entry.value.startPosition, entry.value.endPosition))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
def prefix = fragment.substring(0, lastDash+1)
|
|
||||||
def suffix = fragment.substring(lastDash+1)
|
|
||||||
def addRangeClosure
|
|
||||||
|
|
||||||
if (suffix.charAt(0) == '(') {
|
|
||||||
addRangeClosure = { String key, DeclarationData value ->
|
|
||||||
int index = key.lastIndexOf('-') + 1
|
|
||||||
if (DescriptorMatcher.matchMethodDescriptors(suffix, key.substring(index))) {
|
|
||||||
ranges.add(new DocumentRange(value.startPosition, value.endPosition))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
addRangeClosure = { String key, DeclarationData value ->
|
|
||||||
int index = key.lastIndexOf('-') + 1
|
|
||||||
if (DescriptorMatcher.matchFieldDescriptors(suffix, key.substring(index))) {
|
|
||||||
ranges.add(new DocumentRange(value.startPosition, value.endPosition))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fragment.charAt(0) == '*') {
|
|
||||||
// Unknown type
|
|
||||||
String slashAndTypeNameAndName = prefix.substring(1)
|
|
||||||
String typeNameAndName = prefix.substring(2)
|
|
||||||
|
|
||||||
for (def entry : declarations.entrySet()) {
|
|
||||||
if ((entry.key.indexOf(slashAndTypeNameAndName) != -1) || (entry.key.startsWith(typeNameAndName))) {
|
|
||||||
addRangeClosure(entry.key, entry.value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Known type
|
|
||||||
for (def entry : declarations.entrySet()) {
|
|
||||||
if (entry.key.startsWith(prefix)) {
|
|
||||||
addRangeClosure(entry.key, entry.value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Known type and descriptor ==> Search and high light item
|
|
||||||
def data = declarations.get(fragment)
|
|
||||||
if (data) {
|
|
||||||
ranges.add(new DocumentRange(data.startPosition, data.endPosition))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@CompileStatic
|
|
||||||
static void matchQueryAndAddDocumentRange(
|
|
||||||
Map<String, String> parameters,
|
|
||||||
HashMap<String, DeclarationData> declarations, TreeMap<Integer, HyperlinkPage.HyperlinkData> hyperlinks, ArrayList<StringData> strings,
|
|
||||||
List<DocumentRange> ranges) {
|
|
||||||
|
|
||||||
def highlightFlags = parameters.get('highlightFlags')
|
|
||||||
def highlightPattern = parameters.get('highlightPattern')
|
|
||||||
|
|
||||||
if (highlightFlags && highlightPattern) {
|
|
||||||
def highlightScope = parameters.get('highlightScope')
|
|
||||||
def regexp = createRegExp(highlightPattern)
|
|
||||||
def pattern = Pattern.compile(regexp + '.*')
|
|
||||||
|
|
||||||
if (highlightFlags.indexOf('s') != -1) {
|
|
||||||
// Highlight strings
|
|
||||||
def patternForString = Pattern.compile(regexp)
|
|
||||||
|
|
||||||
for (def data : strings) {
|
|
||||||
if (matchScope(highlightScope, data.owner)) {
|
|
||||||
def matcher = patternForString.matcher(data.text)
|
|
||||||
int offset = data.startPosition
|
|
||||||
|
|
||||||
while(matcher.find()) {
|
|
||||||
ranges.add(new DocumentRange(offset + matcher.start(), offset + matcher.end()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean t = (highlightFlags.indexOf('t') != -1) // Highlight types
|
|
||||||
boolean f = (highlightFlags.indexOf('f') != -1) // Highlight fields
|
|
||||||
boolean m = (highlightFlags.indexOf('m') != -1) // Highlight methods
|
|
||||||
boolean c = (highlightFlags.indexOf('c') != -1) // Highlight constructors
|
|
||||||
|
|
||||||
if (highlightFlags.indexOf('d') != -1) {
|
|
||||||
// Highlight declarations
|
|
||||||
for (def entry : declarations.entrySet()) {
|
|
||||||
def declaration = entry.value
|
|
||||||
|
|
||||||
if (matchScope(highlightScope, declaration.type)) {
|
|
||||||
if ((t && declaration.isAType()) || (c && declaration.isAConstructor())) {
|
|
||||||
matchAndAddDocumentRange(pattern, getMostInnerTypeName(declaration.type), declaration.startPosition, declaration.endPosition, ranges)
|
|
||||||
}
|
|
||||||
if ((f && declaration.isAField()) || (m && declaration.isAMethod())) {
|
|
||||||
matchAndAddDocumentRange(pattern, declaration.name, declaration.startPosition, declaration.endPosition, ranges)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (highlightFlags.indexOf('r') != -1) {
|
|
||||||
// Highlight references
|
|
||||||
for (def entry : hyperlinks.entrySet()) {
|
|
||||||
def hyperlink = entry.value
|
|
||||||
def reference = ((HyperlinkReferenceData)hyperlink).reference
|
|
||||||
|
|
||||||
if (matchScope(highlightScope, reference.owner)) {
|
|
||||||
if ((t && reference.isAType()) || (c && reference.isAConstructor())) {
|
|
||||||
matchAndAddDocumentRange(pattern, getMostInnerTypeName(reference.type), hyperlink.startPosition, hyperlink.endPosition, ranges)
|
|
||||||
}
|
|
||||||
if ((f && reference.isAField()) || (m && reference.isAMethod())) {
|
|
||||||
matchAndAddDocumentRange(pattern, reference.name, hyperlink.startPosition, hyperlink.endPosition, ranges)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@CompileStatic
|
|
||||||
static boolean matchScope(String scope, String type) {
|
|
||||||
if (!scope)
|
|
||||||
return true
|
|
||||||
if (scope.charAt(0) == '*')
|
|
||||||
return type.endsWith(scope.substring(1)) || type.equals(scope.substring(2))
|
|
||||||
return type.equals(scope)
|
|
||||||
}
|
|
||||||
|
|
||||||
@CompileStatic
|
|
||||||
static void matchAndAddDocumentRange(Pattern pattern, String text, int start, int end, List<DocumentRange> ranges) {
|
|
||||||
if (pattern.matcher(text).matches()) {
|
|
||||||
ranges.add(new DocumentRange(start, end))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@CompileStatic
|
|
||||||
static String getMostInnerTypeName(String typeName) {
|
|
||||||
int lastPackageSeparatorIndex = typeName.lastIndexOf('/') + 1
|
|
||||||
int lastTypeNameSeparatorIndex = typeName.lastIndexOf('$') + 1
|
|
||||||
int lastIndex = Math.max(lastPackageSeparatorIndex, lastTypeNameSeparatorIndex)
|
|
||||||
return typeName.substring(lastIndex)
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- FocusedTypeGettable --- //
|
|
||||||
String getFocusedTypeName() { typeDeclarations.floorEntry(textArea.caretPosition)?.value?.type }
|
|
||||||
|
|
||||||
Container.Entry getEntry() { entry }
|
|
||||||
|
|
||||||
// --- PreferencesChangeListener --- //
|
// --- PreferencesChangeListener --- //
|
||||||
void preferencesChanged(Map<String, String> preferences) {
|
void preferencesChanged(Map<String, String> preferences) {
|
||||||
def caret = textArea.caret
|
def caret = textArea.caret
|
||||||
@ -477,18 +140,16 @@ class ClassFilePage
|
|||||||
|
|
||||||
@CompileStatic
|
@CompileStatic
|
||||||
class Printer extends ClassFileSourcePrinter {
|
class Printer extends ClassFileSourcePrinter {
|
||||||
protected StringBuffer stringBuffer
|
protected StringBuffer stringBuffer = new StringBuffer(10*1024)
|
||||||
protected boolean realignmentLineNumber
|
protected boolean realignmentLineNumber
|
||||||
protected boolean showPrefixThis
|
protected boolean showPrefixThis
|
||||||
protected boolean unicodeEscape
|
protected boolean unicodeEscape
|
||||||
protected HashMap<String, ReferenceData> referencesCache
|
protected HashMap<String, TypePage.ReferenceData> referencesCache = new HashMap<>()
|
||||||
|
|
||||||
Printer(GuiPreferences preferences) {
|
Printer(GuiPreferences preferences) {
|
||||||
this.stringBuffer = new StringBuffer(10*1024)
|
|
||||||
this.realignmentLineNumber = preferences.getRealignmentLineNumber()
|
this.realignmentLineNumber = preferences.getRealignmentLineNumber()
|
||||||
this.showPrefixThis = preferences.isShowPrefixThis()
|
this.showPrefixThis = preferences.isShowPrefixThis()
|
||||||
this.unicodeEscape = preferences.isUnicodeEscape()
|
this.unicodeEscape = preferences.isUnicodeEscape()
|
||||||
this.referencesCache = new HashMap<>()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean getRealignmentLineNumber() { realignmentLineNumber }
|
boolean getRealignmentLineNumber() { realignmentLineNumber }
|
||||||
@ -496,8 +157,7 @@ class ClassFilePage
|
|||||||
boolean isUnicodeEscape() { unicodeEscape }
|
boolean isUnicodeEscape() { unicodeEscape }
|
||||||
|
|
||||||
void append(char c) { stringBuffer.append(c) }
|
void append(char c) { stringBuffer.append(c) }
|
||||||
void append(String s) {
|
void append(String s) { stringBuffer.append(s) }
|
||||||
stringBuffer.append(s) }
|
|
||||||
|
|
||||||
// Manage line number and misalignment
|
// Manage line number and misalignment
|
||||||
int textAreaLineNumber = 1
|
int textAreaLineNumber = 1
|
||||||
@ -526,52 +186,52 @@ class ClassFilePage
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Manage strings --- //
|
// --- Add strings --- //
|
||||||
void printString(String s, String scopeInternalName) {
|
void printString(String s, String scopeInternalName) {
|
||||||
strings.add(new StringData(stringBuffer.length(), s.length(), s, scopeInternalName))
|
strings.add(new TypePage.StringData(stringBuffer.length(), s.length(), s, scopeInternalName))
|
||||||
super.printString(s, scopeInternalName)
|
super.printString(s, scopeInternalName)
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Manage references --- //
|
// --- Add references --- //
|
||||||
void printTypeImport(String internalName, String name) {
|
void printTypeImport(String internalName, String name) {
|
||||||
addHyperlink(new HyperlinkReferenceData(stringBuffer.length(), name.length(), newReferenceData(internalName, null, null, null)))
|
addHyperlink(new TypePage.HyperlinkReferenceData(stringBuffer.length(), name.length(), newReferenceData(internalName, null, null, null)))
|
||||||
super.printTypeImport(internalName, name)
|
super.printTypeImport(internalName, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
void printType(String internalName, String name, String scopeInternalName) {
|
void printType(String internalName, String name, String scopeInternalName) {
|
||||||
addHyperlink(new HyperlinkReferenceData(stringBuffer.length(), name.length(), newReferenceData(internalName, null, null, scopeInternalName)))
|
addHyperlink(new TypePage.HyperlinkReferenceData(stringBuffer.length(), name.length(), newReferenceData(internalName, null, null, scopeInternalName)))
|
||||||
super.printType(internalName, name, scopeInternalName)
|
super.printType(internalName, name, scopeInternalName)
|
||||||
}
|
}
|
||||||
|
|
||||||
void printField(String internalName, String name, String descriptor, String scopeInternalName) {
|
void printField(String internalName, String name, String descriptor, String scopeInternalName) {
|
||||||
addHyperlink(new HyperlinkReferenceData(stringBuffer.length(), name.length(), newReferenceData(internalName, name, descriptor, scopeInternalName)))
|
addHyperlink(new TypePage.HyperlinkReferenceData(stringBuffer.length(), name.length(), newReferenceData(internalName, name, descriptor, scopeInternalName)))
|
||||||
super.printField(internalName, name, descriptor, scopeInternalName)
|
super.printField(internalName, name, descriptor, scopeInternalName)
|
||||||
}
|
}
|
||||||
void printStaticField(String internalName, String name, String descriptor, String scopeInternalName) {
|
void printStaticField(String internalName, String name, String descriptor, String scopeInternalName) {
|
||||||
addHyperlink(new HyperlinkReferenceData(stringBuffer.length(), name.length(), newReferenceData(internalName, name, descriptor, scopeInternalName)))
|
addHyperlink(new TypePage.HyperlinkReferenceData(stringBuffer.length(), name.length(), newReferenceData(internalName, name, descriptor, scopeInternalName)))
|
||||||
super.printStaticField(internalName, name, descriptor, scopeInternalName)
|
super.printStaticField(internalName, name, descriptor, scopeInternalName)
|
||||||
}
|
}
|
||||||
|
|
||||||
void printConstructor(String internalName, String name, String descriptor, String scopeInternalName) {
|
void printConstructor(String internalName, String name, String descriptor, String scopeInternalName) {
|
||||||
addHyperlink(new HyperlinkReferenceData(stringBuffer.length(), name.length(), newReferenceData(internalName, "<init>", descriptor, scopeInternalName)))
|
addHyperlink(new TypePage.HyperlinkReferenceData(stringBuffer.length(), name.length(), newReferenceData(internalName, "<init>", descriptor, scopeInternalName)))
|
||||||
super.printConstructor(internalName, name, descriptor, scopeInternalName)
|
super.printConstructor(internalName, name, descriptor, scopeInternalName)
|
||||||
}
|
}
|
||||||
|
|
||||||
void printMethod(String internalName, String name, String descriptor, String scopeInternalName) {
|
void printMethod(String internalName, String name, String descriptor, String scopeInternalName) {
|
||||||
addHyperlink(new HyperlinkReferenceData(stringBuffer.length(), name.length(), newReferenceData(internalName, name, descriptor, scopeInternalName)))
|
addHyperlink(new TypePage.HyperlinkReferenceData(stringBuffer.length(), name.length(), newReferenceData(internalName, name, descriptor, scopeInternalName)))
|
||||||
super.printMethod(internalName, name, descriptor, scopeInternalName)
|
super.printMethod(internalName, name, descriptor, scopeInternalName)
|
||||||
}
|
}
|
||||||
void printStaticMethod(String internalName, String name, String descriptor, String scopeInternalName) {
|
void printStaticMethod(String internalName, String name, String descriptor, String scopeInternalName) {
|
||||||
addHyperlink(new HyperlinkReferenceData(stringBuffer.length(), name.length(), newReferenceData(internalName, name, descriptor, scopeInternalName)))
|
addHyperlink(new TypePage.HyperlinkReferenceData(stringBuffer.length(), name.length(), newReferenceData(internalName, name, descriptor, scopeInternalName)))
|
||||||
super.printStaticMethod(internalName, name, descriptor, scopeInternalName)
|
super.printStaticMethod(internalName, name, descriptor, scopeInternalName)
|
||||||
}
|
}
|
||||||
|
|
||||||
ReferenceData newReferenceData(String internalName, String name, String descriptor, String scopeInternalName) {
|
TypePage.ReferenceData newReferenceData(String internalName, String name, String descriptor, String scopeInternalName) {
|
||||||
def key = internalName + '-' + name + '-'+ descriptor + '-' + scopeInternalName
|
def key = internalName + '-' + name + '-'+ descriptor + '-' + scopeInternalName
|
||||||
def reference = referencesCache.get(key)
|
def reference = referencesCache.get(key)
|
||||||
|
|
||||||
if (reference == null) {
|
if (reference == null) {
|
||||||
reference = new ReferenceData(internalName, name, descriptor, scopeInternalName)
|
reference = new TypePage.ReferenceData(internalName, name, descriptor, scopeInternalName)
|
||||||
referencesCache.put(key, reference)
|
referencesCache.put(key, reference)
|
||||||
references.add(reference)
|
references.add(reference)
|
||||||
}
|
}
|
||||||
@ -579,132 +239,37 @@ class ClassFilePage
|
|||||||
return reference
|
return reference
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Manage declarations --- //
|
// --- Add declarations --- //
|
||||||
void printTypeDeclaration(String internalName, String name) {
|
void printTypeDeclaration(String internalName, String name) {
|
||||||
def data = new DeclarationData(stringBuffer.length(), name.length(), internalName, null, null)
|
def data = new TypePage.DeclarationData(stringBuffer.length(), name.length(), internalName, null, null)
|
||||||
declarations.put(internalName, data)
|
declarations.put(internalName, data)
|
||||||
typeDeclarations.put(stringBuffer.length(), data)
|
typeDeclarations.put(stringBuffer.length(), data)
|
||||||
super.printTypeDeclaration(internalName, name)
|
super.printTypeDeclaration(internalName, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
void printFieldDeclaration(String internalName, String name, String descriptor) {
|
void printFieldDeclaration(String internalName, String name, String descriptor) {
|
||||||
declarations.put(internalName + '-' + name + '-' + descriptor, new DeclarationData(stringBuffer.length(), name.length(), internalName, name, descriptor))
|
declarations.put(internalName + '-' + name + '-' + descriptor, new TypePage.DeclarationData(stringBuffer.length(), name.length(), internalName, name, descriptor))
|
||||||
super.printFieldDeclaration(internalName, name, descriptor)
|
super.printFieldDeclaration(internalName, name, descriptor)
|
||||||
}
|
}
|
||||||
void printStaticFieldDeclaration(String internalName, String name, String descriptor) {
|
void printStaticFieldDeclaration(String internalName, String name, String descriptor) {
|
||||||
declarations.put(internalName + '-' + name + '-' + descriptor, new DeclarationData(stringBuffer.length(), name.length(), internalName, name, descriptor))
|
declarations.put(internalName + '-' + name + '-' + descriptor, new TypePage.DeclarationData(stringBuffer.length(), name.length(), internalName, name, descriptor))
|
||||||
super.printStaticFieldDeclaration(internalName, name, descriptor)
|
super.printStaticFieldDeclaration(internalName, name, descriptor)
|
||||||
}
|
}
|
||||||
|
|
||||||
void printConstructorDeclaration(String internalName, String name, String descriptor) {
|
void printConstructorDeclaration(String internalName, String name, String descriptor) {
|
||||||
declarations.put(internalName + '-<init>-' + descriptor, new DeclarationData(stringBuffer.length(), name.length(), internalName, "<init>", descriptor))
|
declarations.put(internalName + '-<init>-' + descriptor, new TypePage.DeclarationData(stringBuffer.length(), name.length(), internalName, "<init>", descriptor))
|
||||||
super.printConstructorDeclaration(internalName, name, descriptor)
|
super.printConstructorDeclaration(internalName, name, descriptor)
|
||||||
}
|
}
|
||||||
|
|
||||||
void printMethodDeclaration(String internalName, String name, String descriptor) {
|
void printMethodDeclaration(String internalName, String name, String descriptor) {
|
||||||
declarations.put(internalName + '-' + name + '-' + descriptor, new DeclarationData(stringBuffer.length(), name.length(), internalName, name, descriptor))
|
declarations.put(internalName + '-' + name + '-' + descriptor, new TypePage.DeclarationData(stringBuffer.length(), name.length(), internalName, name, descriptor))
|
||||||
super.printMethodDeclaration(internalName, name, descriptor)
|
super.printMethodDeclaration(internalName, name, descriptor)
|
||||||
}
|
}
|
||||||
void printStaticMethodDeclaration(String internalName, String name, String descriptor) {
|
void printStaticMethodDeclaration(String internalName, String name, String descriptor) {
|
||||||
declarations.put(internalName + '-' + name + '-' + descriptor, new DeclarationData(stringBuffer.length(), name.length(), internalName, name, descriptor))
|
declarations.put(internalName + '-' + name + '-' + descriptor, new TypePage.DeclarationData(stringBuffer.length(), name.length(), internalName, name, descriptor))
|
||||||
super.printStaticMethodDeclaration(internalName, name, descriptor)
|
super.printStaticMethodDeclaration(internalName, name, descriptor)
|
||||||
}
|
}
|
||||||
|
|
||||||
String toString() { stringBuffer.toString() }
|
String toString() { stringBuffer.toString() }
|
||||||
}
|
}
|
||||||
|
|
||||||
@CompileStatic
|
|
||||||
static class StringData {
|
|
||||||
int startPosition
|
|
||||||
int endPosition
|
|
||||||
String text
|
|
||||||
String owner
|
|
||||||
|
|
||||||
StringData(int startPosition, int length, String text, String owner) {
|
|
||||||
this.startPosition = startPosition
|
|
||||||
this.endPosition = startPosition + length
|
|
||||||
this.text = text
|
|
||||||
this.owner = owner
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@CompileStatic
|
|
||||||
static class DeclarationData {
|
|
||||||
int startPosition
|
|
||||||
int endPosition
|
|
||||||
String type
|
|
||||||
/**
|
|
||||||
* Field or method name or null for type
|
|
||||||
*/
|
|
||||||
String name
|
|
||||||
String descriptor
|
|
||||||
|
|
||||||
DeclarationData(int startPosition, int length, String type, String name, String descriptor) {
|
|
||||||
this.startPosition = startPosition
|
|
||||||
this.endPosition = startPosition + length
|
|
||||||
this.type = type
|
|
||||||
this.name = name
|
|
||||||
this.descriptor = descriptor
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean isAType() { name == null }
|
|
||||||
boolean isAField() { descriptor && descriptor.charAt(0) != '('}
|
|
||||||
boolean isAMethod() { descriptor && descriptor.charAt(0) == '('}
|
|
||||||
boolean isAConstructor() { "<init>".equals(name) }
|
|
||||||
}
|
|
||||||
|
|
||||||
@CompileStatic
|
|
||||||
static class HyperlinkReferenceData extends HyperlinkPage.HyperlinkData {
|
|
||||||
ReferenceData reference
|
|
||||||
|
|
||||||
HyperlinkReferenceData(int startPosition, int length, ReferenceData reference) {
|
|
||||||
super(startPosition, startPosition+length)
|
|
||||||
this.reference = reference
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@CompileStatic
|
|
||||||
static class ReferenceData {
|
|
||||||
String type
|
|
||||||
/**
|
|
||||||
* Field or method name or null for type
|
|
||||||
*/
|
|
||||||
String name
|
|
||||||
/**
|
|
||||||
* Field or method descriptor or null for type
|
|
||||||
*/
|
|
||||||
String descriptor
|
|
||||||
/**
|
|
||||||
* Internal type name containing reference or null for "import" statement.
|
|
||||||
* Used to high light items matching with URI like "file://dir1/dir2/file?highlightPattern=hello&highlightFlags=drtcmfs&highlightScope=type".
|
|
||||||
*/
|
|
||||||
String owner
|
|
||||||
/**
|
|
||||||
* "Enabled" flag for link of reference
|
|
||||||
*/
|
|
||||||
boolean enabled = false
|
|
||||||
|
|
||||||
ReferenceData(String type, String name, String descriptor, String owner) {
|
|
||||||
this.type = type
|
|
||||||
this.name = name
|
|
||||||
this.descriptor = descriptor
|
|
||||||
this.owner = owner
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean isAType() { name == null }
|
|
||||||
boolean isAField() { descriptor && descriptor.charAt(0) != '('}
|
|
||||||
boolean isAMethod() { descriptor && descriptor.charAt(0) == '('}
|
|
||||||
boolean isAConstructor() { "<init>".equals(name) }
|
|
||||||
}
|
|
||||||
|
|
||||||
@CompileStatic
|
|
||||||
protected static boolean getPreferenceValue(Map<String, String> preferences, String key, boolean defaultValue) {
|
|
||||||
String v = preferences.get(key);
|
|
||||||
|
|
||||||
if (v == null) {
|
|
||||||
return defaultValue;
|
|
||||||
} else {
|
|
||||||
return Boolean.valueOf(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ import org.fife.ui.rsyntaxtextarea.SyntaxConstants
|
|||||||
|
|
||||||
import java.awt.*
|
import java.awt.*
|
||||||
|
|
||||||
class EjbJarXmlFilePage extends TypeHyperlinkPage implements UriGettable, IndexesChangeListener {
|
class EjbJarXmlFilePage extends TypeReferencePage implements UriGettable, IndexesChangeListener {
|
||||||
protected API api
|
protected API api
|
||||||
protected Container.Entry entry
|
protected Container.Entry entry
|
||||||
protected Collection<Indexes> collectionOfIndexes
|
protected Collection<Indexes> collectionOfIndexes
|
||||||
@ -133,7 +133,7 @@ class EjbJarXmlFilePage extends TypeHyperlinkPage implements UriGettable, Indexe
|
|||||||
int startIndex = position + text.indexOf(trim)
|
int startIndex = position + text.indexOf(trim)
|
||||||
int endIndex = startIndex + trim.length()
|
int endIndex = startIndex + trim.length()
|
||||||
def internalTypeName = trim.replace('.', '/')
|
def internalTypeName = trim.replace('.', '/')
|
||||||
addHyperlink(new TypeHyperlinkPage.TypeHyperlinkData(startIndex, endIndex, internalTypeName))
|
addHyperlink(new TypeReferencePage.TypeHyperlinkData(startIndex, endIndex, internalTypeName))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,735 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2008-2015 Emmanuel Dupuy
|
||||||
|
* This program is made available under the terms of the GPLv3 License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package jd.gui.view.component
|
||||||
|
|
||||||
|
import groovy.transform.CompileStatic
|
||||||
|
import jd.gui.api.API
|
||||||
|
import jd.gui.api.model.Container
|
||||||
|
import jd.gui.util.parser.antlr.ANTLRParser
|
||||||
|
import jd.gui.util.parser.antlr.AbstractJavaListener
|
||||||
|
import jd.gui.util.parser.antlr.JavaParser
|
||||||
|
import org.antlr.v4.runtime.ANTLRInputStream
|
||||||
|
import org.antlr.v4.runtime.ParserRuleContext
|
||||||
|
import org.antlr.v4.runtime.tree.ParseTree
|
||||||
|
import org.antlr.v4.runtime.tree.TerminalNode
|
||||||
|
import org.fife.ui.rsyntaxtextarea.SyntaxConstants
|
||||||
|
|
||||||
|
class JavaFilePage extends TypePage {
|
||||||
|
|
||||||
|
JavaFilePage(API api, Container.Entry entry) {
|
||||||
|
super(api, entry)
|
||||||
|
// Load content file
|
||||||
|
def text = entry.inputStream.text.replace('\r\n', '\n').replace('\r', '\n')
|
||||||
|
// Parse
|
||||||
|
def declarationListener = new DeclarationListener(entry)
|
||||||
|
def referenceListener = new ReferenceListener(entry)
|
||||||
|
|
||||||
|
ANTLRParser.parse(new ANTLRInputStream(text), declarationListener)
|
||||||
|
referenceListener.init(declarationListener)
|
||||||
|
ANTLRParser.parse(new ANTLRInputStream(text), referenceListener)
|
||||||
|
// Display
|
||||||
|
setText(text)
|
||||||
|
// Show hyperlinks
|
||||||
|
indexesChanged(api.collectionOfIndexes)
|
||||||
|
}
|
||||||
|
|
||||||
|
String getSyntaxStyle() { SyntaxConstants.SYNTAX_STYLE_JAVA }
|
||||||
|
|
||||||
|
// --- ContentSavable --- //
|
||||||
|
String getFileName() {
|
||||||
|
def path = entry.path
|
||||||
|
int index = path.lastIndexOf('/')
|
||||||
|
return path.substring(index+1)
|
||||||
|
}
|
||||||
|
|
||||||
|
@CompileStatic
|
||||||
|
class DeclarationListener extends AbstractJavaListener {
|
||||||
|
|
||||||
|
protected StringBuffer sbTypeDeclaration = new StringBuffer()
|
||||||
|
protected String currentInternalTypeName
|
||||||
|
|
||||||
|
DeclarationListener(Container.Entry entry) { super(entry) }
|
||||||
|
|
||||||
|
HashMap<String, String> getNameToInternalTypeName() { super.nameToInternalTypeName }
|
||||||
|
|
||||||
|
// --- Add declarations --- //
|
||||||
|
void enterPackageDeclaration(JavaParser.PackageDeclarationContext ctx) {
|
||||||
|
super.enterPackageDeclaration(ctx);
|
||||||
|
|
||||||
|
if (! packageName.isEmpty()) {
|
||||||
|
sbTypeDeclaration.append(packageName).append('/');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void enterImportDeclaration(JavaParser.ImportDeclarationContext ctx) {
|
||||||
|
List<TerminalNode> identifiers = ctx.qualifiedName().Identifier()
|
||||||
|
String internalTypeName = concatIdentifiers(identifiers)
|
||||||
|
String typeName = identifiers.get(identifiers.size()-1).symbol.text
|
||||||
|
|
||||||
|
nameToInternalTypeName.put(typeName, internalTypeName)
|
||||||
|
}
|
||||||
|
|
||||||
|
void enterClassDeclaration(JavaParser.ClassDeclarationContext ctx) { enterTypeDeclaration(ctx); }
|
||||||
|
void exitClassDeclaration(JavaParser.ClassDeclarationContext ctx) { exitTypeDeclaration(); }
|
||||||
|
|
||||||
|
void enterEnumDeclaration(JavaParser.EnumDeclarationContext ctx) { enterTypeDeclaration(ctx); }
|
||||||
|
void exitEnumDeclaration(JavaParser.EnumDeclarationContext ctx) { exitTypeDeclaration(); }
|
||||||
|
|
||||||
|
void enterInterfaceDeclaration(JavaParser.InterfaceDeclarationContext ctx) { enterTypeDeclaration(ctx); }
|
||||||
|
void exitInterfaceDeclaration(JavaParser.InterfaceDeclarationContext ctx) { exitTypeDeclaration(); }
|
||||||
|
|
||||||
|
void enterAnnotationTypeDeclaration(JavaParser.AnnotationTypeDeclarationContext ctx) { enterTypeDeclaration(ctx); }
|
||||||
|
void exitAnnotationTypeDeclaration(JavaParser.AnnotationTypeDeclarationContext ctx) { exitTypeDeclaration(); }
|
||||||
|
|
||||||
|
void enterTypeDeclaration(ParserRuleContext ctx) {
|
||||||
|
// Type declaration
|
||||||
|
def identifier = ctx.getToken(JavaParser.Identifier, 0);
|
||||||
|
def typeName = identifier.text
|
||||||
|
int position = identifier.symbol.startIndex
|
||||||
|
int length = sbTypeDeclaration.length();
|
||||||
|
|
||||||
|
if ((length == 0) || (sbTypeDeclaration.charAt(length-1) == '/')) {
|
||||||
|
sbTypeDeclaration.append(typeName);
|
||||||
|
} else {
|
||||||
|
sbTypeDeclaration.append('$').append(typeName);
|
||||||
|
}
|
||||||
|
|
||||||
|
currentInternalTypeName = sbTypeDeclaration.toString()
|
||||||
|
nameToInternalTypeName.put(typeName, currentInternalTypeName);
|
||||||
|
|
||||||
|
// Super type reference
|
||||||
|
JavaParser.TypeContext superType = ctx.getRuleContext(JavaParser.TypeContext.class, 0)
|
||||||
|
String superInternalTypeName = superType ? resolveInternalTypeName(superType.classOrInterfaceType().Identifier()) : null
|
||||||
|
|
||||||
|
def data = new TypeDeclarationData(position, typeName.length(), currentInternalTypeName, null, null, superInternalTypeName)
|
||||||
|
|
||||||
|
declarations.put(currentInternalTypeName, data)
|
||||||
|
typeDeclarations.put(position, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
void exitTypeDeclaration() {
|
||||||
|
int index = sbTypeDeclaration.lastIndexOf('$');
|
||||||
|
|
||||||
|
if (index == -1) {
|
||||||
|
index = sbTypeDeclaration.lastIndexOf('/') + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index == -1) {
|
||||||
|
sbTypeDeclaration.setLength(0);
|
||||||
|
} else {
|
||||||
|
sbTypeDeclaration.setLength(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
currentInternalTypeName = sbTypeDeclaration.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
public void enterClassBodyDeclaration(JavaParser.ClassBodyDeclarationContext ctx) {
|
||||||
|
if (ctx.getChildCount() == 2) {
|
||||||
|
def first = ctx.getChild(0);
|
||||||
|
|
||||||
|
if (first instanceof TerminalNode) {
|
||||||
|
if (first.getSymbol().type == JavaParser.STATIC) {
|
||||||
|
String name = first.text
|
||||||
|
int position = first.getSymbol().startIndex
|
||||||
|
declarations.put(currentInternalTypeName + '-<clinit>-()V', new TypePage.DeclarationData(position, 5, currentInternalTypeName, name, '()V'))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void enterConstDeclaration(JavaParser.ConstDeclarationContext ctx) {
|
||||||
|
def typeContext = ctx.type();
|
||||||
|
|
||||||
|
for (def constantDeclaratorContext : ctx.constantDeclarator()) {
|
||||||
|
def identifier = constantDeclaratorContext.Identifier()
|
||||||
|
def name = identifier.text
|
||||||
|
int dimensionOnVariable = countDimension(constantDeclaratorContext.children)
|
||||||
|
def descriptor = createDescriptor(typeContext, dimensionOnVariable)
|
||||||
|
int position = identifier.symbol.startIndex
|
||||||
|
|
||||||
|
declarations.put(currentInternalTypeName + '-' + name + '-' + descriptor, new TypePage.DeclarationData(position, name.length(), currentInternalTypeName, name, descriptor))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void enterFieldDeclaration(JavaParser.FieldDeclarationContext ctx) {
|
||||||
|
def typeContext = ctx.type();
|
||||||
|
|
||||||
|
for (JavaParser.VariableDeclaratorContext declaration : ctx.variableDeclarators().variableDeclarator()) {
|
||||||
|
def variableDeclaratorId = declaration.variableDeclaratorId()
|
||||||
|
def identifier = variableDeclaratorId.Identifier()
|
||||||
|
def name = identifier.text
|
||||||
|
int dimensionOnVariable = countDimension(variableDeclaratorId.children)
|
||||||
|
def descriptor = createDescriptor(typeContext, dimensionOnVariable)
|
||||||
|
int position = identifier.symbol.startIndex
|
||||||
|
def data = new TypePage.DeclarationData(position, name.length(), currentInternalTypeName, name, descriptor)
|
||||||
|
|
||||||
|
declarations.put(currentInternalTypeName + '-' + name + '-' + descriptor, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void enterMethodDeclaration(JavaParser.MethodDeclarationContext ctx) {
|
||||||
|
enterMethodDeclaration(ctx, ctx.Identifier(), ctx.formalParameters(), ctx.type());
|
||||||
|
}
|
||||||
|
|
||||||
|
void enterInterfaceMethodDeclaration(JavaParser.InterfaceMethodDeclarationContext ctx) {
|
||||||
|
enterMethodDeclaration(ctx, ctx.Identifier(), ctx.formalParameters(), ctx.type());
|
||||||
|
}
|
||||||
|
|
||||||
|
void enterMethodDeclaration(
|
||||||
|
ParserRuleContext ctx, TerminalNode identifier,
|
||||||
|
JavaParser.FormalParametersContext formalParameters, JavaParser.TypeContext returnType) {
|
||||||
|
|
||||||
|
def name = identifier.text
|
||||||
|
def paramDescriptors = createParamDescriptors(formalParameters.formalParameterList())
|
||||||
|
def returnDescriptor = createDescriptor(returnType, 0)
|
||||||
|
def descriptor = paramDescriptors + returnDescriptor
|
||||||
|
int position = identifier.symbol.startIndex
|
||||||
|
|
||||||
|
declarations.put(currentInternalTypeName + '-' + name + '-' + descriptor, new TypePage.DeclarationData(position, name.length(), currentInternalTypeName, name, descriptor))
|
||||||
|
}
|
||||||
|
|
||||||
|
void enterConstructorDeclaration(JavaParser.ConstructorDeclarationContext ctx) {
|
||||||
|
def identifier = ctx.Identifier()
|
||||||
|
def name = identifier.text
|
||||||
|
def paramDescriptors = createParamDescriptors(ctx.formalParameters().formalParameterList())
|
||||||
|
def descriptor = paramDescriptors + "V"
|
||||||
|
int position = identifier.symbol.startIndex
|
||||||
|
|
||||||
|
declarations.put(currentInternalTypeName + '-<init>-' + descriptor, new TypePage.DeclarationData(position, name.length(), currentInternalTypeName, name, descriptor))
|
||||||
|
}
|
||||||
|
|
||||||
|
String createParamDescriptors(JavaParser.FormalParameterListContext formalParameterList) {
|
||||||
|
StringBuffer paramDescriptors = null
|
||||||
|
|
||||||
|
if (formalParameterList != null) {
|
||||||
|
def formalParameters = formalParameterList.formalParameter()
|
||||||
|
paramDescriptors = new StringBuffer("(")
|
||||||
|
|
||||||
|
for (def formalParameter : formalParameters) {
|
||||||
|
int dimensionOnParameter = countDimension(formalParameter.variableDeclaratorId().children)
|
||||||
|
def descriptor = createDescriptor(formalParameter.type(), dimensionOnParameter)
|
||||||
|
|
||||||
|
paramDescriptors.append(descriptor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (paramDescriptors == null) ? "()" : paramDescriptors.append(')').toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@CompileStatic
|
||||||
|
class ReferenceListener extends AbstractJavaListener {
|
||||||
|
|
||||||
|
protected StringBuffer sbTypeDeclaration = new StringBuffer()
|
||||||
|
protected HashMap<String, TypePage.ReferenceData> referencesCache = new HashMap<>()
|
||||||
|
protected String currentInternalTypeName
|
||||||
|
protected Context currentContext = null
|
||||||
|
|
||||||
|
ReferenceListener(Container.Entry entry) { super(entry) }
|
||||||
|
|
||||||
|
void init(DeclarationListener declarationListener) {
|
||||||
|
this.nameToInternalTypeName.putAll(declarationListener.nameToInternalTypeName)
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Add declarations --- //
|
||||||
|
void enterPackageDeclaration(JavaParser.PackageDeclarationContext ctx) {
|
||||||
|
super.enterPackageDeclaration(ctx);
|
||||||
|
|
||||||
|
if (! packageName.isEmpty()) {
|
||||||
|
sbTypeDeclaration.append(packageName).append('/');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void enterImportDeclaration(JavaParser.ImportDeclarationContext ctx) {
|
||||||
|
List<TerminalNode> identifiers = ctx.qualifiedName().Identifier()
|
||||||
|
int position = identifiers.get(0).symbol.startIndex
|
||||||
|
String internalTypeName = concatIdentifiers(identifiers)
|
||||||
|
|
||||||
|
addHyperlink(new TypePage.HyperlinkReferenceData(position, internalTypeName.length(), newReferenceData(internalTypeName, null, null, null)))
|
||||||
|
}
|
||||||
|
|
||||||
|
void enterClassDeclaration(JavaParser.ClassDeclarationContext ctx) { enterTypeDeclaration(ctx); }
|
||||||
|
void exitClassDeclaration(JavaParser.ClassDeclarationContext ctx) { exitTypeDeclaration(); }
|
||||||
|
|
||||||
|
void enterEnumDeclaration(JavaParser.EnumDeclarationContext ctx) { enterTypeDeclaration(ctx); }
|
||||||
|
void exitEnumDeclaration(JavaParser.EnumDeclarationContext ctx) { exitTypeDeclaration(); }
|
||||||
|
|
||||||
|
void enterInterfaceDeclaration(JavaParser.InterfaceDeclarationContext ctx) { enterTypeDeclaration(ctx); }
|
||||||
|
void exitInterfaceDeclaration(JavaParser.InterfaceDeclarationContext ctx) { exitTypeDeclaration(); }
|
||||||
|
|
||||||
|
void enterAnnotationTypeDeclaration(JavaParser.AnnotationTypeDeclarationContext ctx) { enterTypeDeclaration(ctx); }
|
||||||
|
void exitAnnotationTypeDeclaration(JavaParser.AnnotationTypeDeclarationContext ctx) { exitTypeDeclaration(); }
|
||||||
|
|
||||||
|
void enterTypeDeclaration(ParserRuleContext ctx) {
|
||||||
|
// Type declaration
|
||||||
|
def identifier = ctx.getToken(JavaParser.Identifier, 0);
|
||||||
|
def typeName = identifier.text
|
||||||
|
int length = sbTypeDeclaration.length();
|
||||||
|
|
||||||
|
if ((length == 0) || (sbTypeDeclaration.charAt(length-1) == '/')) {
|
||||||
|
sbTypeDeclaration.append(typeName);
|
||||||
|
} else {
|
||||||
|
sbTypeDeclaration.append('$').append(typeName);
|
||||||
|
}
|
||||||
|
|
||||||
|
currentInternalTypeName = sbTypeDeclaration.toString()
|
||||||
|
currentContext = new Context(currentContext)
|
||||||
|
}
|
||||||
|
|
||||||
|
void exitTypeDeclaration() {
|
||||||
|
int index = sbTypeDeclaration.lastIndexOf('$');
|
||||||
|
|
||||||
|
if (index == -1) {
|
||||||
|
index = sbTypeDeclaration.lastIndexOf('/') + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index == -1) {
|
||||||
|
sbTypeDeclaration.setLength(0);
|
||||||
|
} else {
|
||||||
|
sbTypeDeclaration.setLength(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
currentInternalTypeName = sbTypeDeclaration.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
void enterFormalParameters(JavaParser.FormalParametersContext ctx) {
|
||||||
|
def formalParameterList = ctx.formalParameterList()
|
||||||
|
|
||||||
|
if (formalParameterList != null) {
|
||||||
|
def formalParameters = formalParameterList.formalParameter()
|
||||||
|
|
||||||
|
for (def formalParameter : formalParameters) {
|
||||||
|
int dimensionOnParameter = countDimension(formalParameter.variableDeclaratorId().children)
|
||||||
|
def descriptor = createDescriptor(formalParameter.type(), dimensionOnParameter)
|
||||||
|
def name = formalParameter.variableDeclaratorId().Identifier().symbol.text
|
||||||
|
|
||||||
|
currentContext.nameToDescriptor.put(name, descriptor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Add references --- //
|
||||||
|
void enterType(JavaParser.TypeContext ctx) {
|
||||||
|
// Add type reference
|
||||||
|
def classOrInterfaceType = ctx.classOrInterfaceType()
|
||||||
|
|
||||||
|
if (classOrInterfaceType != null) {
|
||||||
|
def identifiers = classOrInterfaceType.Identifier()
|
||||||
|
def name = concatIdentifiers(identifiers)
|
||||||
|
def internalTypeName = resolveInternalTypeName(identifiers)
|
||||||
|
int position = identifiers.get(0).symbol.startIndex
|
||||||
|
|
||||||
|
addHyperlink(new TypePage.HyperlinkReferenceData(position, name.length(), newReferenceData(internalTypeName, null, null, currentInternalTypeName)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void enterLocalVariableDeclaration(JavaParser.LocalVariableDeclarationContext ctx) {
|
||||||
|
def typeContext = ctx.type()
|
||||||
|
|
||||||
|
for (def variableDeclarator : ctx.variableDeclarators().variableDeclarator()) {
|
||||||
|
def variableDeclaratorId = variableDeclarator.variableDeclaratorId()
|
||||||
|
int dimensionOnVariable = countDimension(variableDeclaratorId.children)
|
||||||
|
def descriptor = createDescriptor(typeContext, dimensionOnVariable)
|
||||||
|
def name = variableDeclarator.variableDeclaratorId().Identifier().getSymbol().getText()
|
||||||
|
|
||||||
|
currentContext.nameToDescriptor.put(name, descriptor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void enterCreator(JavaParser.CreatorContext ctx) {
|
||||||
|
enterNewExpression(ctx.createdName().Identifier(), ctx.classCreatorRest())
|
||||||
|
}
|
||||||
|
|
||||||
|
void enterInnerCreator(JavaParser.InnerCreatorContext ctx) {
|
||||||
|
enterNewExpression(Collections.singletonList(ctx.Identifier()), ctx.classCreatorRest())
|
||||||
|
}
|
||||||
|
|
||||||
|
void enterNewExpression(List<TerminalNode> identifiers, JavaParser.ClassCreatorRestContext classCreatorRest) {
|
||||||
|
if (identifiers.size() > 0) {
|
||||||
|
def name = concatIdentifiers(identifiers)
|
||||||
|
def internalTypeName = resolveInternalTypeName(identifiers)
|
||||||
|
int position = identifiers.get(0).symbol.startIndex
|
||||||
|
|
||||||
|
if (classCreatorRest) {
|
||||||
|
// Constructor call -> Add a link to the constructor declaration
|
||||||
|
def expressionList = classCreatorRest.arguments().expressionList()
|
||||||
|
def descriptor = expressionList ? getParametersDescriptor(expressionList).append('V').toString() : '()V'
|
||||||
|
|
||||||
|
addHyperlink(new TypePage.HyperlinkReferenceData(position, name.length(), newReferenceData(internalTypeName, '<init>', descriptor, currentInternalTypeName)))
|
||||||
|
} else {
|
||||||
|
// New type array -> Add a link to the type declaration
|
||||||
|
addHyperlink(new TypePage.HyperlinkReferenceData(position, name.length(), newReferenceData(internalTypeName, null, null, currentInternalTypeName)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void enterExpression(JavaParser.ExpressionContext ctx) {
|
||||||
|
switch (ctx.getChildCount()) {
|
||||||
|
case 1:
|
||||||
|
TerminalNode identifier0 = getToken(ctx.children, JavaParser.Identifier, 0);
|
||||||
|
|
||||||
|
if (identifier0 != null) {
|
||||||
|
if (isAField(ctx)) {
|
||||||
|
def primaryContext = ctx.primary()
|
||||||
|
|
||||||
|
if (primaryContext) {
|
||||||
|
String fieldName = primaryContext.literal().StringLiteral();
|
||||||
|
|
||||||
|
if (!currentContext.getDescriptor(fieldName) != null) {
|
||||||
|
// Not a local variable or a method parameter
|
||||||
|
def fieldTypeName = searchInternalTypeNameForThisFieldName(currentInternalTypeName, fieldName)
|
||||||
|
int position = ctx.Identifier().getSymbol().startIndex
|
||||||
|
|
||||||
|
addHyperlink(new TypePage.HyperlinkReferenceData(position, fieldName.length(), newReferenceData(fieldTypeName, fieldName, '?', currentInternalTypeName)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
def identifier = ctx.primary().Identifier()
|
||||||
|
|
||||||
|
if (identifier) {
|
||||||
|
def symbol = identifier.getSymbol()
|
||||||
|
def name = symbol.text
|
||||||
|
def internalTypeName = nameToInternalTypeName.get(name)
|
||||||
|
|
||||||
|
if (internalTypeName) {
|
||||||
|
int position = symbol.startIndex
|
||||||
|
|
||||||
|
addHyperlink(new TypePage.HyperlinkReferenceData(position, name.length(), newReferenceData(internalTypeName, null, null, currentInternalTypeName)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
if (getToken(ctx.children, JavaParser.DOT, 1) != null) {
|
||||||
|
// Search "expression '.' Identifier" : field reference
|
||||||
|
def identifier3 = getToken(ctx.children, JavaParser.Identifier, 2);
|
||||||
|
|
||||||
|
if ((identifier3 != null) && isAField(ctx)) {
|
||||||
|
def fieldTypeName = getInternalTypeName(ctx.getChild(0))
|
||||||
|
|
||||||
|
if (fieldTypeName) {
|
||||||
|
int position = identifier3.symbol.startIndex
|
||||||
|
def fieldName = identifier3.getText()
|
||||||
|
|
||||||
|
addHyperlink(new TypePage.HyperlinkReferenceData(position, fieldName.length(), newReferenceData(fieldTypeName, fieldName, '?', currentInternalTypeName)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (getToken(ctx.children, JavaParser.LPAREN, 1) != null) {
|
||||||
|
// Search "expression '(' ')'" : method reference
|
||||||
|
if (getToken(ctx.children, JavaParser.RPAREN, 2) != null) {
|
||||||
|
enterCallMethodExpression(ctx, null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
if (getToken(ctx.children, JavaParser.LPAREN, 1) != null) {
|
||||||
|
// Search "expression '(' expressionList ')'" : method reference
|
||||||
|
if (getToken(ctx.children, JavaParser.RPAREN, 3) != null) {
|
||||||
|
def expressionListContext = ctx.expressionList();
|
||||||
|
|
||||||
|
if ((expressionListContext != null) && (expressionListContext == ctx.children.get(2))) {
|
||||||
|
enterCallMethodExpression(ctx, expressionListContext)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void enterCallMethodExpression(JavaParser.ExpressionContext ctx, JavaParser.ExpressionListContext expressionListContext) {
|
||||||
|
ParseTree first = ctx.children.get(0)
|
||||||
|
|
||||||
|
if (first instanceof JavaParser.ExpressionContext) {
|
||||||
|
switch (first.getChildCount()) {
|
||||||
|
case 1:
|
||||||
|
def primary = first.primary()
|
||||||
|
def identifier = primary.Identifier()
|
||||||
|
|
||||||
|
if (identifier) {
|
||||||
|
def symbol = identifier.getSymbol()
|
||||||
|
|
||||||
|
if (symbol) {
|
||||||
|
String methodName = symbol.text
|
||||||
|
String methodTypeName = searchInternalTypeNameForThisMethodName(currentInternalTypeName, methodName)
|
||||||
|
|
||||||
|
if (methodTypeName) {
|
||||||
|
int position = symbol.startIndex
|
||||||
|
def methodDescriptor = expressionListContext ? getParametersDescriptor(expressionListContext).append('?').toString() : '()?'
|
||||||
|
|
||||||
|
addHyperlink(new TypePage.HyperlinkReferenceData(position, methodName.length(), newReferenceData(methodTypeName, methodName, methodDescriptor, currentInternalTypeName)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
def symbol = primary.getChild(TerminalNode.class, 0).getSymbol()
|
||||||
|
|
||||||
|
if (symbol) {
|
||||||
|
switch (symbol.type) {
|
||||||
|
case JavaParser.THIS:
|
||||||
|
int position = symbol.startIndex
|
||||||
|
def methodDescriptor = expressionListContext ? getParametersDescriptor(expressionListContext).append('?').toString() : '()?'
|
||||||
|
|
||||||
|
addHyperlink(new TypePage.HyperlinkReferenceData(position, 4, newReferenceData(currentInternalTypeName, '<init>', methodDescriptor, currentInternalTypeName)))
|
||||||
|
break
|
||||||
|
case JavaParser.SUPER:
|
||||||
|
def data = declarations.get(currentInternalTypeName)
|
||||||
|
|
||||||
|
if (data instanceof TypeDeclarationData) {
|
||||||
|
int position = symbol.startIndex
|
||||||
|
def methodTypeName = ((TypeDeclarationData) data).superTypeName
|
||||||
|
def methodDescriptor = expressionListContext ? getParametersDescriptor(expressionListContext).append('?').toString() : '()?'
|
||||||
|
|
||||||
|
addHyperlink(new TypePage.HyperlinkReferenceData(position, 5, newReferenceData(methodTypeName, '<init>', methodDescriptor, currentInternalTypeName)))
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 3:
|
||||||
|
// Search "expression '.' Identifier"
|
||||||
|
ParseTree dot = first.getChild(1)
|
||||||
|
|
||||||
|
if ((dot instanceof TerminalNode) && (dot.getSymbol().getType() == JavaParser.DOT)) {
|
||||||
|
ParseTree identifier3 = first.getChild(2)
|
||||||
|
|
||||||
|
if ((identifier3 instanceof TerminalNode) && (identifier3.getSymbol().type == JavaParser.Identifier)) {
|
||||||
|
String methodTypeName = getInternalTypeName(first.getChild(0))
|
||||||
|
|
||||||
|
if (methodTypeName) {
|
||||||
|
int position = identifier3.getSymbol().startIndex
|
||||||
|
def methodName = identifier3.getText()
|
||||||
|
def methodDescriptor = expressionListContext ? getParametersDescriptor(expressionListContext).append('?').toString() : '()?'
|
||||||
|
|
||||||
|
addHyperlink(new TypePage.HyperlinkReferenceData(position, methodName.length(), newReferenceData(methodTypeName, methodName, methodDescriptor, currentInternalTypeName)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuffer getParametersDescriptor(JavaParser.ExpressionListContext expressionListContext) {
|
||||||
|
def sb = new StringBuffer('(')
|
||||||
|
for (def exp : expressionListContext.expression()) sb.append('?')
|
||||||
|
sb.append(')')
|
||||||
|
return sb
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isAField(JavaParser.ExpressionContext ctx) {
|
||||||
|
def parent = ctx.parent
|
||||||
|
|
||||||
|
if (parent instanceof JavaParser.ExpressionContext) {
|
||||||
|
int size = parent.getChildCount();
|
||||||
|
|
||||||
|
if (parent.getChild(size - 1) != ctx) {
|
||||||
|
for (int i=0; i<size; i++) {
|
||||||
|
if (parent.getChild(i) == ctx) {
|
||||||
|
def next = parent.getChild(i+1)
|
||||||
|
|
||||||
|
if (next instanceof TerminalNode) {
|
||||||
|
switch (next.getSymbol().getType()) {
|
||||||
|
case JavaParser.DOT:
|
||||||
|
case JavaParser.LPAREN:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
String getInternalTypeName(ParseTree pt) {
|
||||||
|
if (pt instanceof JavaParser.ExpressionContext) {
|
||||||
|
|
||||||
|
if (pt.getChildCount() == 1) {
|
||||||
|
def primary = pt.primary()
|
||||||
|
def identifier = primary.Identifier()
|
||||||
|
|
||||||
|
if (identifier) {
|
||||||
|
String name = identifier.getSymbol().text
|
||||||
|
String descriptor = currentContext.getDescriptor(name);
|
||||||
|
|
||||||
|
if (descriptor) {
|
||||||
|
// Is a local variable or a method parameter
|
||||||
|
if (descriptor.charAt(0) == 'L') {
|
||||||
|
return descriptor.substring(1, descriptor.length() - 1)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
String internalTypeName = searchInternalTypeNameForThisFieldName(currentInternalTypeName, name)
|
||||||
|
|
||||||
|
if (internalTypeName) {
|
||||||
|
// Is a field
|
||||||
|
return internalTypeName
|
||||||
|
} else {
|
||||||
|
internalTypeName = resolveInternalTypeName(Collections.singletonList(identifier))
|
||||||
|
|
||||||
|
if (internalTypeName) {
|
||||||
|
// Is a type
|
||||||
|
return internalTypeName
|
||||||
|
} else {
|
||||||
|
// Not found
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
def symbol = primary.getChild(TerminalNode.class, 0)?.getSymbol()
|
||||||
|
|
||||||
|
if (symbol) {
|
||||||
|
switch (symbol.type) {
|
||||||
|
case JavaParser.THIS:
|
||||||
|
return currentInternalTypeName
|
||||||
|
case JavaParser.SUPER:
|
||||||
|
def data = declarations.get(currentInternalTypeName)
|
||||||
|
|
||||||
|
if (data instanceof TypeDeclarationData) {
|
||||||
|
return ((TypeDeclarationData)data).superTypeName
|
||||||
|
} else {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
String searchInternalTypeNameForThisFieldName(String internalTypeName, String name) {
|
||||||
|
String prefix = internalTypeName + '-' + name + '-'
|
||||||
|
int length = prefix.length()
|
||||||
|
|
||||||
|
for (def entry : declarations.entrySet()) {
|
||||||
|
if (entry.key.startsWith(prefix) && (entry.key.charAt(length) != '(')) {
|
||||||
|
return entry.value.typeName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not found
|
||||||
|
int index = internalTypeName.lastIndexOf('$')
|
||||||
|
|
||||||
|
if (index != -1) {
|
||||||
|
// Search in the outer type
|
||||||
|
internalTypeName = internalTypeName.substring(0, index)
|
||||||
|
|
||||||
|
return searchInternalTypeNameForThisFieldName(internalTypeName, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not found
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
String searchInternalTypeNameForThisMethodName(String internalTypeName, String name) {
|
||||||
|
String prefix = internalTypeName + '-' + name + '-('
|
||||||
|
|
||||||
|
for (def entry : declarations.entrySet()) {
|
||||||
|
if (entry.key.startsWith(prefix)) {
|
||||||
|
return entry.value.typeName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not found
|
||||||
|
int index = internalTypeName.lastIndexOf('$')
|
||||||
|
|
||||||
|
if (index != -1) {
|
||||||
|
// Search in the outer type
|
||||||
|
internalTypeName = internalTypeName.substring(0, index)
|
||||||
|
|
||||||
|
return searchInternalTypeNameForThisMethodName(internalTypeName, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not found
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
TerminalNode getToken(List<ParseTree> children, int type, int i) {
|
||||||
|
ParseTree pt = children.get(i);
|
||||||
|
|
||||||
|
if (pt instanceof TerminalNode) {
|
||||||
|
if (((TerminalNode)pt).getSymbol().getType() == type) {
|
||||||
|
return (TerminalNode)pt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
void enterBlock(JavaParser.BlockContext ctx) {
|
||||||
|
currentContext = new Context(currentContext)
|
||||||
|
}
|
||||||
|
|
||||||
|
void exitBlock(JavaParser.BlockContext ctx) {
|
||||||
|
currentContext = currentContext.outerContext
|
||||||
|
}
|
||||||
|
|
||||||
|
TypePage.ReferenceData newReferenceData(String internalName, String name, String descriptor, String scopeInternalName) {
|
||||||
|
def key = internalName + '-' + name + '-'+ descriptor + '-' + scopeInternalName
|
||||||
|
def reference = referencesCache.get(key)
|
||||||
|
|
||||||
|
if (reference == null) {
|
||||||
|
reference = new TypePage.ReferenceData(internalName, name, descriptor, scopeInternalName)
|
||||||
|
referencesCache.put(key, reference)
|
||||||
|
references.add(reference)
|
||||||
|
}
|
||||||
|
|
||||||
|
return reference
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Add strings --- //
|
||||||
|
void enterLiteral(JavaParser.LiteralContext ctx) {
|
||||||
|
def stringLiteral = ctx.StringLiteral()
|
||||||
|
|
||||||
|
if (stringLiteral != null) {
|
||||||
|
String str = stringLiteral.getSymbol().getText()
|
||||||
|
int position = stringLiteral.getSymbol().getStartIndex()
|
||||||
|
|
||||||
|
strings.add(new TypePage.StringData(position, str.length(), str, currentInternalTypeName))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@CompileStatic
|
||||||
|
static class Context {
|
||||||
|
Context outerContext
|
||||||
|
|
||||||
|
HashMap<String, String> nameToDescriptor = new HashMap<>()
|
||||||
|
|
||||||
|
Context(Context outerContext) {
|
||||||
|
this.outerContext = outerContext
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param name Parameter or variable name
|
||||||
|
* @return Qualified type name
|
||||||
|
*/
|
||||||
|
String getDescriptor(String name) {
|
||||||
|
String descriptor = nameToDescriptor.get(name)
|
||||||
|
|
||||||
|
if ((descriptor == null) && (outerContext != null)) {
|
||||||
|
descriptor = outerContext.getDescriptor(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return descriptor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@CompileStatic
|
||||||
|
static class TypeDeclarationData extends TypePage.DeclarationData {
|
||||||
|
String superTypeName
|
||||||
|
|
||||||
|
TypeDeclarationData(int startPosition, int length, String type, String name, String descriptor, String superTypeName) {
|
||||||
|
super(startPosition, length, type, name, descriptor)
|
||||||
|
|
||||||
|
this.superTypeName = superTypeName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -213,7 +213,7 @@ class TextPage extends JPanel implements ContentCopyable, ContentSelectable, Lin
|
|||||||
|
|
||||||
// --- LineNumberNavigable --- //
|
// --- LineNumberNavigable --- //
|
||||||
int getMaximumLineNumber() {
|
int getMaximumLineNumber() {
|
||||||
return textArea.getLineOfOffset(textArea.document.length)
|
return textArea.getLineOfOffset(textArea.document.length) + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
void goToLineNumber(int lineNumber) {
|
void goToLineNumber(int lineNumber) {
|
||||||
|
457
services/src/main/groovy/jd/gui/view/component/TypePage.groovy
Normal file
457
services/src/main/groovy/jd/gui/view/component/TypePage.groovy
Normal file
@ -0,0 +1,457 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2008-2015 Emmanuel Dupuy
|
||||||
|
* This program is made available under the terms of the GPLv3 License.
|
||||||
|
*/
|
||||||
|
package jd.gui.view.component
|
||||||
|
|
||||||
|
import groovy.transform.CompileStatic
|
||||||
|
import jd.gui.api.API
|
||||||
|
import jd.gui.api.feature.FocusedTypeGettable
|
||||||
|
import jd.gui.api.feature.IndexesChangeListener
|
||||||
|
import jd.gui.api.feature.UriGettable
|
||||||
|
import jd.gui.api.feature.UriOpenable
|
||||||
|
import jd.gui.api.model.Container
|
||||||
|
import jd.gui.api.model.Indexes
|
||||||
|
import jd.gui.util.matcher.DescriptorMatcher
|
||||||
|
import org.fife.ui.rsyntaxtextarea.DocumentRange
|
||||||
|
|
||||||
|
import java.awt.Point
|
||||||
|
import java.util.regex.Pattern
|
||||||
|
|
||||||
|
abstract class TypePage extends CustomLineNumbersPage implements UriGettable, UriOpenable, IndexesChangeListener, FocusedTypeGettable {
|
||||||
|
|
||||||
|
protected API api
|
||||||
|
protected Container.Entry entry
|
||||||
|
protected Collection<Indexes> collectionOfIndexes
|
||||||
|
|
||||||
|
protected HashMap<String, DeclarationData> declarations = new HashMap<>()
|
||||||
|
protected TreeMap<Integer, DeclarationData> typeDeclarations = new TreeMap<>()
|
||||||
|
protected ArrayList<ReferenceData> references = new ArrayList<>()
|
||||||
|
protected ArrayList<StringData> strings = new ArrayList<>()
|
||||||
|
|
||||||
|
TypePage(API api, Container.Entry entry) {
|
||||||
|
// Init attributes
|
||||||
|
this.api = api
|
||||||
|
this.entry = entry
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean isHyperlinkEnabled(HyperlinkPage.HyperlinkData hyperlinkData) { hyperlinkData.reference.enabled }
|
||||||
|
|
||||||
|
protected void openHyperlink(int x, int y, HyperlinkPage.HyperlinkData hyperlinkData) {
|
||||||
|
if (hyperlinkData.reference.enabled) {
|
||||||
|
// Save current position in history
|
||||||
|
def location = textArea.getLocationOnScreen()
|
||||||
|
int offset = textArea.viewToModel(new Point(x-location.x as int, y-location.y as int))
|
||||||
|
def uri = entry.uri
|
||||||
|
api.addURI(new URI(uri.scheme, uri.authority, uri.path, 'position=' + offset, null))
|
||||||
|
|
||||||
|
// Open link
|
||||||
|
ReferenceData reference = hyperlinkData.reference
|
||||||
|
def typeName = reference.typeName
|
||||||
|
def entries = collectionOfIndexes?.collect { it.getIndex('typeDeclarations')?.get(typeName) }.flatten().grep { it != null }
|
||||||
|
def fragment = typeName
|
||||||
|
|
||||||
|
if (reference.name) {
|
||||||
|
fragment += '-' + reference.name
|
||||||
|
}
|
||||||
|
if (reference.descriptor) {
|
||||||
|
fragment += '-' + reference.descriptor
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entries.contains(entry)) {
|
||||||
|
api.openURI(new URI(uri.scheme, uri.authority, uri.path, fragment))
|
||||||
|
} else {
|
||||||
|
def rootUri = entry.container.root.uri.toString()
|
||||||
|
def sameContainerEntries = entries?.grep { it.uri.toString().startsWith(rootUri) }
|
||||||
|
|
||||||
|
if (sameContainerEntries) {
|
||||||
|
api.openURI(x, y, sameContainerEntries, null, fragment)
|
||||||
|
} else if (entries) {
|
||||||
|
api.openURI(x, y, entries, null, fragment)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- UriGettable --- //
|
||||||
|
URI getUri() { entry.uri }
|
||||||
|
|
||||||
|
// --- UriOpenable --- //
|
||||||
|
/**
|
||||||
|
* @param uri for URI format, @see jd.gui.api.feature.UriOpenable
|
||||||
|
*/
|
||||||
|
boolean openUri(URI uri) {
|
||||||
|
List<DocumentRange> ranges = []
|
||||||
|
def fragment = uri.fragment
|
||||||
|
def query = uri.query
|
||||||
|
|
||||||
|
textArea.highlighter.clearMarkAllHighlights()
|
||||||
|
|
||||||
|
if (fragment) {
|
||||||
|
matchFragmentAndAddDocumentRange(fragment, declarations, ranges)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (query) {
|
||||||
|
Map<String, String> parameters = parseQuery(query)
|
||||||
|
|
||||||
|
if (parameters.containsKey('lineNumber')) {
|
||||||
|
def lineNumber = parameters.get('lineNumber')
|
||||||
|
if (lineNumber.isNumber()) {
|
||||||
|
goToLineNumber(lineNumber.toInteger())
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
} else if (parameters.containsKey('position')) {
|
||||||
|
def position = parameters.get('position')
|
||||||
|
if (position.isNumber()) {
|
||||||
|
int pos = position.toInteger()
|
||||||
|
if (textArea.document.length > pos) {
|
||||||
|
ranges.add(new DocumentRange(pos, pos))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
matchQueryAndAddDocumentRange(parameters, declarations, hyperlinks, strings, ranges)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ranges) {
|
||||||
|
textArea.markAllHighlightColor = SELECT_HIGHLIGHT_COLOR
|
||||||
|
textArea.markAll(ranges)
|
||||||
|
setCaretPositionAndCenter(ranges.sort().get(0))
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
@CompileStatic
|
||||||
|
static void matchFragmentAndAddDocumentRange(
|
||||||
|
String fragment, HashMap<String, DeclarationData> declarations, List<DocumentRange> ranges) {
|
||||||
|
|
||||||
|
if ((fragment.indexOf('?') != -1) || (fragment.indexOf('*') != -1)) {
|
||||||
|
// Unknown type and/or descriptor ==> Select all and scroll to the first one
|
||||||
|
int lastDash = fragment.lastIndexOf('-')
|
||||||
|
|
||||||
|
if (lastDash == -1) {
|
||||||
|
// Search types
|
||||||
|
String slashAndTypeName = fragment.substring(1)
|
||||||
|
String typeName = fragment.substring(2)
|
||||||
|
|
||||||
|
for (def entry : declarations.entrySet()) {
|
||||||
|
if (entry.key.endsWith(slashAndTypeName) || entry.key.equals(typeName)) {
|
||||||
|
ranges.add(new DocumentRange(entry.value.startPosition, entry.value.endPosition))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
def prefix = fragment.substring(0, lastDash+1)
|
||||||
|
def suffix = fragment.substring(lastDash+1)
|
||||||
|
def addRangeClosure
|
||||||
|
|
||||||
|
if (suffix.charAt(0) == '(') {
|
||||||
|
addRangeClosure = { String key, DeclarationData value ->
|
||||||
|
int index = key.lastIndexOf('-') + 1
|
||||||
|
if (DescriptorMatcher.matchMethodDescriptors(suffix, key.substring(index))) {
|
||||||
|
ranges.add(new DocumentRange(value.startPosition, value.endPosition))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
addRangeClosure = { String key, DeclarationData value ->
|
||||||
|
int index = key.lastIndexOf('-') + 1
|
||||||
|
if (DescriptorMatcher.matchFieldDescriptors(suffix, key.substring(index))) {
|
||||||
|
ranges.add(new DocumentRange(value.startPosition, value.endPosition))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fragment.charAt(0) == '*') {
|
||||||
|
// Unknown type
|
||||||
|
String slashAndTypeNameAndName = prefix.substring(1)
|
||||||
|
String typeNameAndName = prefix.substring(2)
|
||||||
|
|
||||||
|
for (def entry : declarations.entrySet()) {
|
||||||
|
if ((entry.key.indexOf(slashAndTypeNameAndName) != -1) || (entry.key.startsWith(typeNameAndName))) {
|
||||||
|
addRangeClosure(entry.key, entry.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Known type
|
||||||
|
for (def entry : declarations.entrySet()) {
|
||||||
|
if (entry.key.startsWith(prefix)) {
|
||||||
|
addRangeClosure(entry.key, entry.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Known type and descriptor ==> Search and high light item
|
||||||
|
def data = declarations.get(fragment)
|
||||||
|
if (data) {
|
||||||
|
ranges.add(new DocumentRange(data.startPosition, data.endPosition))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@CompileStatic
|
||||||
|
static void matchQueryAndAddDocumentRange(
|
||||||
|
Map<String, String> parameters,
|
||||||
|
HashMap<String, DeclarationData> declarations, TreeMap<Integer, HyperlinkPage.HyperlinkData> hyperlinks, ArrayList<StringData> strings,
|
||||||
|
List<DocumentRange> ranges) {
|
||||||
|
|
||||||
|
def highlightFlags = parameters.get('highlightFlags')
|
||||||
|
def highlightPattern = parameters.get('highlightPattern')
|
||||||
|
|
||||||
|
if (highlightFlags && highlightPattern) {
|
||||||
|
def highlightScope = parameters.get('highlightScope')
|
||||||
|
def regexp = createRegExp(highlightPattern)
|
||||||
|
def pattern = Pattern.compile(regexp + '.*')
|
||||||
|
|
||||||
|
if (highlightFlags.indexOf('s') != -1) {
|
||||||
|
// Highlight strings
|
||||||
|
def patternForString = Pattern.compile(regexp)
|
||||||
|
|
||||||
|
for (def data : strings) {
|
||||||
|
if (matchScope(highlightScope, data.owner)) {
|
||||||
|
def matcher = patternForString.matcher(data.text)
|
||||||
|
int offset = data.startPosition
|
||||||
|
|
||||||
|
while(matcher.find()) {
|
||||||
|
ranges.add(new DocumentRange(offset + matcher.start(), offset + matcher.end()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean t = (highlightFlags.indexOf('t') != -1) // Highlight types
|
||||||
|
boolean f = (highlightFlags.indexOf('f') != -1) // Highlight fields
|
||||||
|
boolean m = (highlightFlags.indexOf('m') != -1) // Highlight methods
|
||||||
|
boolean c = (highlightFlags.indexOf('c') != -1) // Highlight constructors
|
||||||
|
|
||||||
|
if (highlightFlags.indexOf('d') != -1) {
|
||||||
|
// Highlight declarations
|
||||||
|
for (def entry : declarations.entrySet()) {
|
||||||
|
def declaration = entry.value
|
||||||
|
|
||||||
|
if (matchScope(highlightScope, declaration.typeName)) {
|
||||||
|
if ((t && declaration.isAType()) || (c && declaration.isAConstructor())) {
|
||||||
|
matchAndAddDocumentRange(pattern, getMostInnerTypeName(declaration.typeName), declaration.startPosition, declaration.endPosition, ranges)
|
||||||
|
}
|
||||||
|
if ((f && declaration.isAField()) || (m && declaration.isAMethod())) {
|
||||||
|
matchAndAddDocumentRange(pattern, declaration.name, declaration.startPosition, declaration.endPosition, ranges)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (highlightFlags.indexOf('r') != -1) {
|
||||||
|
// Highlight references
|
||||||
|
for (def entry : hyperlinks.entrySet()) {
|
||||||
|
def hyperlink = entry.value
|
||||||
|
def reference = ((HyperlinkReferenceData)hyperlink).reference
|
||||||
|
|
||||||
|
if (matchScope(highlightScope, reference.owner)) {
|
||||||
|
if ((t && reference.isAType()) || (c && reference.isAConstructor())) {
|
||||||
|
matchAndAddDocumentRange(pattern, getMostInnerTypeName(reference.typeName), hyperlink.startPosition, hyperlink.endPosition, ranges)
|
||||||
|
}
|
||||||
|
if ((f && reference.isAField()) || (m && reference.isAMethod())) {
|
||||||
|
matchAndAddDocumentRange(pattern, reference.name, hyperlink.startPosition, hyperlink.endPosition, ranges)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@CompileStatic
|
||||||
|
static boolean matchScope(String scope, String type) {
|
||||||
|
if (!scope)
|
||||||
|
return true
|
||||||
|
if (scope.charAt(0) == '*')
|
||||||
|
return type.endsWith(scope.substring(1)) || type.equals(scope.substring(2))
|
||||||
|
return type.equals(scope)
|
||||||
|
}
|
||||||
|
|
||||||
|
@CompileStatic
|
||||||
|
static void matchAndAddDocumentRange(Pattern pattern, String text, int start, int end, List<DocumentRange> ranges) {
|
||||||
|
if (pattern.matcher(text).matches()) {
|
||||||
|
ranges.add(new DocumentRange(start, end))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@CompileStatic
|
||||||
|
static String getMostInnerTypeName(String typeName) {
|
||||||
|
int lastPackageSeparatorIndex = typeName.lastIndexOf('/') + 1
|
||||||
|
int lastTypeNameSeparatorIndex = typeName.lastIndexOf('$') + 1
|
||||||
|
int lastIndex = Math.max(lastPackageSeparatorIndex, lastTypeNameSeparatorIndex)
|
||||||
|
return typeName.substring(lastIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- FocusedTypeGettable --- //
|
||||||
|
String getFocusedTypeName() { typeDeclarations.floorEntry(textArea.caretPosition)?.value?.typeName }
|
||||||
|
|
||||||
|
Container.Entry getEntry() { entry }
|
||||||
|
|
||||||
|
// --- IndexesChangeListener --- //
|
||||||
|
@CompileStatic
|
||||||
|
void indexesChanged(Collection<Indexes> collectionOfIndexes) {
|
||||||
|
// Update the list of containers
|
||||||
|
this.collectionOfIndexes = collectionOfIndexes
|
||||||
|
// Refresh links
|
||||||
|
boolean refresh = false
|
||||||
|
|
||||||
|
for (def reference : references) {
|
||||||
|
def typeName = reference.typeName
|
||||||
|
boolean enabled
|
||||||
|
|
||||||
|
if (reference.name) {
|
||||||
|
typeName = searchTypeHavingMember(typeName, reference.name, reference.descriptor, entry)
|
||||||
|
if (typeName) {
|
||||||
|
// Replace type with the real type containing the referenced member
|
||||||
|
reference.typeName = typeName
|
||||||
|
enabled = true
|
||||||
|
} else {
|
||||||
|
enabled = false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
enabled = collectionOfIndexes.find { it.getIndex('typeDeclarations')?.get(typeName) } != null
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reference.enabled != enabled) {
|
||||||
|
reference.enabled = enabled
|
||||||
|
refresh = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (refresh) {
|
||||||
|
textArea.repaint()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String searchTypeHavingMember(String typeName, String name, String descriptor, Container.Entry entry) {
|
||||||
|
def entries = collectionOfIndexes?.collect { it.getIndex('typeDeclarations')?.get(typeName) }.flatten().grep { it!=null }
|
||||||
|
def rootUri = entry.container.root.uri.toString()
|
||||||
|
def sameContainerEntries = entries?.grep { Container.Entry e -> e.uri.toString().startsWith(rootUri) }
|
||||||
|
|
||||||
|
if (sameContainerEntries) {
|
||||||
|
return searchTypeHavingMember(typeName, name, descriptor, sameContainerEntries)
|
||||||
|
} else {
|
||||||
|
return searchTypeHavingMember(typeName, name, descriptor, entries)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@CompileStatic
|
||||||
|
protected String searchTypeHavingMember(String typeName, String name, String descriptor, List<Container.Entry> entries) {
|
||||||
|
for (def entry : entries) {
|
||||||
|
def type = api.getTypeFactory(entry).make(api, entry, typeName)
|
||||||
|
|
||||||
|
if (type) {
|
||||||
|
if (descriptor.indexOf('(') == -1) {
|
||||||
|
// Search a field
|
||||||
|
for (def field : type.fields) {
|
||||||
|
if (field.name.equals(name) && DescriptorMatcher.matchFieldDescriptors(field.descriptor, descriptor)) {
|
||||||
|
// Field found
|
||||||
|
return typeName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Search a method
|
||||||
|
for (def method : type.methods) {
|
||||||
|
if (method.name.equals(name) && DescriptorMatcher.matchMethodDescriptors(method.descriptor, descriptor)) {
|
||||||
|
// Method found
|
||||||
|
return typeName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not found -> Search in super type
|
||||||
|
def typeOwnerName = searchTypeHavingMember(type.superName, name, descriptor, entry)
|
||||||
|
if (typeOwnerName) {
|
||||||
|
return typeOwnerName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
@CompileStatic
|
||||||
|
static class StringData {
|
||||||
|
int startPosition
|
||||||
|
int endPosition
|
||||||
|
String text
|
||||||
|
String owner
|
||||||
|
|
||||||
|
StringData(int startPosition, int length, String text, String owner) {
|
||||||
|
this.startPosition = startPosition
|
||||||
|
this.endPosition = startPosition + length
|
||||||
|
this.text = text
|
||||||
|
this.owner = owner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@CompileStatic
|
||||||
|
static class DeclarationData {
|
||||||
|
int startPosition
|
||||||
|
int endPosition
|
||||||
|
String typeName
|
||||||
|
/**
|
||||||
|
* Field or method name or null for type
|
||||||
|
*/
|
||||||
|
String name
|
||||||
|
String descriptor
|
||||||
|
|
||||||
|
DeclarationData(int startPosition, int length, String typeName, String name, String descriptor) {
|
||||||
|
this.startPosition = startPosition
|
||||||
|
this.endPosition = startPosition + length
|
||||||
|
this.typeName = typeName
|
||||||
|
this.name = name
|
||||||
|
this.descriptor = descriptor
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isAType() { name == null }
|
||||||
|
boolean isAField() { descriptor && descriptor.charAt(0) != '('}
|
||||||
|
boolean isAMethod() { descriptor && descriptor.charAt(0) == '('}
|
||||||
|
boolean isAConstructor() { "<init>".equals(name) }
|
||||||
|
}
|
||||||
|
|
||||||
|
@CompileStatic
|
||||||
|
static class HyperlinkReferenceData extends HyperlinkPage.HyperlinkData {
|
||||||
|
ReferenceData reference
|
||||||
|
|
||||||
|
HyperlinkReferenceData(int startPosition, int length, ReferenceData reference) {
|
||||||
|
super(startPosition, startPosition+length)
|
||||||
|
this.reference = reference
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@CompileStatic
|
||||||
|
static class ReferenceData {
|
||||||
|
String typeName
|
||||||
|
/**
|
||||||
|
* Field or method name or null for type
|
||||||
|
*/
|
||||||
|
String name
|
||||||
|
/**
|
||||||
|
* Field or method descriptor or null for type
|
||||||
|
*/
|
||||||
|
String descriptor
|
||||||
|
/**
|
||||||
|
* Internal type name containing reference or null for "import" statement.
|
||||||
|
* Used to high light items matching with URI like "file://dir1/dir2/file?highlightPattern=hello&highlightFlags=drtcmfs&highlightScope=type".
|
||||||
|
*/
|
||||||
|
String owner
|
||||||
|
/**
|
||||||
|
* "Enabled" flag for link of reference
|
||||||
|
*/
|
||||||
|
boolean enabled = false
|
||||||
|
|
||||||
|
ReferenceData(String typeName, String name, String descriptor, String owner) {
|
||||||
|
this.typeName = typeName
|
||||||
|
this.name = name
|
||||||
|
this.descriptor = descriptor
|
||||||
|
this.owner = owner
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isAType() { name == null }
|
||||||
|
boolean isAField() { descriptor && descriptor.charAt(0) != '('}
|
||||||
|
boolean isAMethod() { descriptor && descriptor.charAt(0) == '('}
|
||||||
|
boolean isAConstructor() { "<init>".equals(name) }
|
||||||
|
}
|
||||||
|
}
|
@ -10,7 +10,10 @@ import org.fife.ui.rsyntaxtextarea.DocumentRange
|
|||||||
|
|
||||||
import java.util.regex.Pattern
|
import java.util.regex.Pattern
|
||||||
|
|
||||||
abstract class TypeHyperlinkPage extends HyperlinkPage {
|
/**
|
||||||
|
* Page containing type references (Hyperlinks to pages of type)
|
||||||
|
*/
|
||||||
|
abstract class TypeReferencePage extends HyperlinkPage {
|
||||||
|
|
||||||
// --- UriOpenable --- //
|
// --- UriOpenable --- //
|
||||||
boolean openUri(URI uri) {
|
boolean openUri(URI uri) {
|
@ -16,7 +16,7 @@ import org.fife.ui.rsyntaxtextarea.SyntaxConstants
|
|||||||
import java.awt.Point
|
import java.awt.Point
|
||||||
|
|
||||||
|
|
||||||
class WebXmlFilePage extends TypeHyperlinkPage implements UriGettable, IndexesChangeListener {
|
class WebXmlFilePage extends TypeReferencePage implements UriGettable, IndexesChangeListener {
|
||||||
protected API api
|
protected API api
|
||||||
protected Container.Entry entry
|
protected Container.Entry entry
|
||||||
protected Collection<Indexes> collectionOfIndexes
|
protected Collection<Indexes> collectionOfIndexes
|
||||||
@ -47,7 +47,7 @@ class WebXmlFilePage extends TypeHyperlinkPage implements UriGettable, IndexesCh
|
|||||||
api.addURI(new URI(uri.scheme, uri.authority, uri.path, 'position=' + offset, null))
|
api.addURI(new URI(uri.scheme, uri.authority, uri.path, 'position=' + offset, null))
|
||||||
|
|
||||||
// Open link
|
// Open link
|
||||||
if (hyperlinkData instanceof TypeHyperlinkPage.TypeHyperlinkData) {
|
if (hyperlinkData instanceof TypeReferencePage.TypeHyperlinkData) {
|
||||||
def internalTypeName = hyperlinkData.internalTypeName
|
def internalTypeName = hyperlinkData.internalTypeName
|
||||||
def entries = collectionOfIndexes?.collect { it.getIndex('typeDeclarations')?.get(internalTypeName) }.flatten().grep { it!=null }
|
def entries = collectionOfIndexes?.collect { it.getIndex('typeDeclarations')?.get(internalTypeName) }.flatten().grep { it!=null }
|
||||||
def rootUri = entry.container.root.uri.toString()
|
def rootUri = entry.container.root.uri.toString()
|
||||||
@ -163,7 +163,7 @@ class WebXmlFilePage extends TypeHyperlinkPage implements UriGettable, IndexesCh
|
|||||||
addHyperlink(new PathHyperlinkData(startIndex, endIndex, trim))
|
addHyperlink(new PathHyperlinkData(startIndex, endIndex, trim))
|
||||||
} else {
|
} else {
|
||||||
def internalTypeName = trim.replace('.', '/')
|
def internalTypeName = trim.replace('.', '/')
|
||||||
addHyperlink(new TypeHyperlinkPage.TypeHyperlinkData(startIndex, endIndex, internalTypeName))
|
addHyperlink(new TypeReferencePage.TypeHyperlinkData(startIndex, endIndex, internalTypeName))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,13 +5,13 @@
|
|||||||
|
|
||||||
package jd.gui.service.indexer;
|
package jd.gui.service.indexer;
|
||||||
|
|
||||||
|
import jd.gui.api.model.Container;
|
||||||
|
import jd.gui.api.model.Indexes;
|
||||||
import jd.gui.spi.Indexer;
|
import jd.gui.spi.Indexer;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.Arrays;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Properties;
|
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
public abstract class AbstractIndexerProvider implements Indexer {
|
public abstract class AbstractIndexerProvider implements Indexer {
|
||||||
@ -51,4 +51,15 @@ public abstract class AbstractIndexerProvider implements Indexer {
|
|||||||
return (externalSelectors==null) ? null : externalSelectors.toArray(new String[externalSelectors.size()]);
|
return (externalSelectors==null) ? null : externalSelectors.toArray(new String[externalSelectors.size()]);
|
||||||
}
|
}
|
||||||
public Pattern getPathPattern() { return externalPathPattern; }
|
public Pattern getPathPattern() { return externalPathPattern; }
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
protected static void addToIndex(Indexes indexes, String indexName, Set<String> set, Container.Entry entry) {
|
||||||
|
if (set.size() > 0) {
|
||||||
|
Map<String, Collection> index = indexes.getIndex(indexName);
|
||||||
|
|
||||||
|
for (String key : set) {
|
||||||
|
index.get(key).add(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,6 @@ import jd.gui.api.API;
|
|||||||
import jd.gui.api.model.Container;
|
import jd.gui.api.model.Container;
|
||||||
import jd.gui.api.model.Indexes;
|
import jd.gui.api.model.Indexes;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
@ -20,17 +19,17 @@ import java.util.*;
|
|||||||
* Unsafe thread implementation of class file indexer.
|
* Unsafe thread implementation of class file indexer.
|
||||||
*/
|
*/
|
||||||
public class ClassFileIndexerProvider extends AbstractIndexerProvider {
|
public class ClassFileIndexerProvider extends AbstractIndexerProvider {
|
||||||
protected Set<String> typeDeclarationSet = new HashSet<>();
|
protected HashSet<String> typeDeclarationSet = new HashSet<>();
|
||||||
protected Set<String> constructorDeclarationSet = new HashSet<>();
|
protected HashSet<String> constructorDeclarationSet = new HashSet<>();
|
||||||
protected Set<String> methodDeclarationSet = new HashSet<>();
|
protected HashSet<String> methodDeclarationSet = new HashSet<>();
|
||||||
protected Set<String> fieldDeclarationSet = new HashSet<>();
|
protected HashSet<String> fieldDeclarationSet = new HashSet<>();
|
||||||
protected Set<String> typeReferenceSet = new HashSet<>();
|
protected HashSet<String> typeReferenceSet = new HashSet<>();
|
||||||
protected Set<String> constructorReferenceSet = new HashSet<>();
|
protected HashSet<String> constructorReferenceSet = new HashSet<>();
|
||||||
protected Set<String> methodReferenceSet = new HashSet<>();
|
protected HashSet<String> methodReferenceSet = new HashSet<>();
|
||||||
protected Set<String> fieldReferenceSet = new HashSet<>();
|
protected HashSet<String> fieldReferenceSet = new HashSet<>();
|
||||||
protected Set<String> stringSet = new HashSet<>();
|
protected HashSet<String> stringSet = new HashSet<>();
|
||||||
protected Set<String> superTypeNameSet = new HashSet<>();
|
protected HashSet<String> superTypeNameSet = new HashSet<>();
|
||||||
protected Set<String> descriptorSet = new HashSet<>();
|
protected HashSet<String> descriptorSet = new HashSet<>();
|
||||||
|
|
||||||
protected ClassIndexer classIndexer = new ClassIndexer(
|
protected ClassIndexer classIndexer = new ClassIndexer(
|
||||||
typeDeclarationSet, constructorDeclarationSet, methodDeclarationSet,
|
typeDeclarationSet, constructorDeclarationSet, methodDeclarationSet,
|
||||||
@ -72,11 +71,9 @@ public class ClassFileIndexerProvider extends AbstractIndexerProvider {
|
|||||||
superTypeNameSet.clear();
|
superTypeNameSet.clear();
|
||||||
descriptorSet.clear();
|
descriptorSet.clear();
|
||||||
|
|
||||||
InputStream inputStream = null;
|
try (InputStream inputStream = entry.getInputStream()) {
|
||||||
|
|
||||||
try {
|
|
||||||
// Index field, method, interfaces & super type
|
// Index field, method, interfaces & super type
|
||||||
ClassReader classReader = new ClassReader(inputStream = entry.getInputStream());
|
ClassReader classReader = new ClassReader(inputStream);
|
||||||
classReader.accept(classIndexer, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
|
classReader.accept(classIndexer, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
|
||||||
|
|
||||||
// Index descriptors
|
// Index descriptors
|
||||||
@ -159,32 +156,17 @@ public class ClassFileIndexerProvider extends AbstractIndexerProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} catch (Exception ignore) {
|
} catch (Exception ignore) {
|
||||||
} finally {
|
|
||||||
if (inputStream != null) {
|
|
||||||
try { inputStream.close(); } catch (IOException ignore) {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
protected static void addToIndex(Indexes indexes, String indexName, Set<String> set, Container.Entry entry) {
|
|
||||||
if (set.size() > 0) {
|
|
||||||
Map<String, Collection> index = indexes.getIndex(indexName);
|
|
||||||
|
|
||||||
for (String key : set) {
|
|
||||||
index.get(key).add(entry);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static class ClassIndexer extends ClassVisitor {
|
protected static class ClassIndexer extends ClassVisitor {
|
||||||
protected Set<String> typeDeclarationSet;
|
protected HashSet<String> typeDeclarationSet;
|
||||||
protected Set<String> constructorDeclarationSet;
|
protected HashSet<String> constructorDeclarationSet;
|
||||||
protected Set<String> methodDeclarationSet;
|
protected HashSet<String> methodDeclarationSet;
|
||||||
protected Set<String> fieldDeclarationSet;
|
protected HashSet<String> fieldDeclarationSet;
|
||||||
protected Set<String> typeReferenceSet;
|
protected HashSet<String> typeReferenceSet;
|
||||||
protected Set<String> superTypeNameSet;
|
protected HashSet<String> superTypeNameSet;
|
||||||
protected Set<String> descriptorSet;
|
protected HashSet<String> descriptorSet;
|
||||||
|
|
||||||
protected AnnotationIndexer annotationIndexer;
|
protected AnnotationIndexer annotationIndexer;
|
||||||
protected FieldIndexer fieldIndexer;
|
protected FieldIndexer fieldIndexer;
|
||||||
@ -193,9 +175,9 @@ public class ClassFileIndexerProvider extends AbstractIndexerProvider {
|
|||||||
protected String name;
|
protected String name;
|
||||||
|
|
||||||
public ClassIndexer(
|
public ClassIndexer(
|
||||||
Set<String> typeDeclarationSet, Set<String> constructorDeclarationSet,
|
HashSet<String> typeDeclarationSet, HashSet<String> constructorDeclarationSet,
|
||||||
Set<String> methodDeclarationSet, Set<String> fieldDeclarationSet,
|
HashSet<String> methodDeclarationSet, HashSet<String> fieldDeclarationSet,
|
||||||
Set<String> typeReferenceSet, Set<String> superTypeNameSet, Set<String> descriptorSet) {
|
HashSet<String> typeReferenceSet, HashSet<String> superTypeNameSet, HashSet<String> descriptorSet) {
|
||||||
super(Opcodes.ASM5);
|
super(Opcodes.ASM5);
|
||||||
|
|
||||||
this.typeDeclarationSet = typeDeclarationSet;
|
this.typeDeclarationSet = typeDeclarationSet;
|
||||||
@ -258,9 +240,9 @@ public class ClassFileIndexerProvider extends AbstractIndexerProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected static class SignatureIndexer extends SignatureVisitor {
|
protected static class SignatureIndexer extends SignatureVisitor {
|
||||||
protected Set<String> typeReferenceSet;
|
protected HashSet<String> typeReferenceSet;
|
||||||
|
|
||||||
SignatureIndexer(Set<String> typeReferenceSet) {
|
SignatureIndexer(HashSet<String> typeReferenceSet) {
|
||||||
super(Opcodes.ASM5);
|
super(Opcodes.ASM5);
|
||||||
this.typeReferenceSet = typeReferenceSet;
|
this.typeReferenceSet = typeReferenceSet;
|
||||||
}
|
}
|
||||||
@ -271,9 +253,9 @@ public class ClassFileIndexerProvider extends AbstractIndexerProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected static class AnnotationIndexer extends AnnotationVisitor {
|
protected static class AnnotationIndexer extends AnnotationVisitor {
|
||||||
protected Set<String> descriptorSet;
|
protected HashSet<String> descriptorSet;
|
||||||
|
|
||||||
public AnnotationIndexer(Set<String> descriptorSet) {
|
public AnnotationIndexer(HashSet<String> descriptorSet) {
|
||||||
super(Opcodes.ASM5);
|
super(Opcodes.ASM5);
|
||||||
this.descriptorSet = descriptorSet;
|
this.descriptorSet = descriptorSet;
|
||||||
}
|
}
|
||||||
@ -289,10 +271,10 @@ public class ClassFileIndexerProvider extends AbstractIndexerProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected static class FieldIndexer extends FieldVisitor {
|
protected static class FieldIndexer extends FieldVisitor {
|
||||||
protected Set<String> descriptorSet;
|
protected HashSet<String> descriptorSet;
|
||||||
protected AnnotationIndexer annotationIndexer;
|
protected AnnotationIndexer annotationIndexer;
|
||||||
|
|
||||||
public FieldIndexer(Set<String> descriptorSet, AnnotationIndexer annotationInexer) {
|
public FieldIndexer(HashSet<String> descriptorSet, AnnotationIndexer annotationInexer) {
|
||||||
super(Opcodes.ASM5);
|
super(Opcodes.ASM5);
|
||||||
this.descriptorSet = descriptorSet;
|
this.descriptorSet = descriptorSet;
|
||||||
this.annotationIndexer = annotationInexer;
|
this.annotationIndexer = annotationInexer;
|
||||||
@ -310,10 +292,10 @@ public class ClassFileIndexerProvider extends AbstractIndexerProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected static class MethodIndexer extends MethodVisitor {
|
protected static class MethodIndexer extends MethodVisitor {
|
||||||
protected Set<String> descriptorSet;
|
protected HashSet<String> descriptorSet;
|
||||||
protected AnnotationIndexer annotationIndexer;
|
protected AnnotationIndexer annotationIndexer;
|
||||||
|
|
||||||
public MethodIndexer(Set<String> descriptorSet, AnnotationIndexer annotationIndexer) {
|
public MethodIndexer(HashSet<String> descriptorSet, AnnotationIndexer annotationIndexer) {
|
||||||
super(Opcodes.ASM5);
|
super(Opcodes.ASM5);
|
||||||
this.descriptorSet = descriptorSet;
|
this.descriptorSet = descriptorSet;
|
||||||
this.annotationIndexer = annotationIndexer;
|
this.annotationIndexer = annotationIndexer;
|
||||||
|
@ -0,0 +1,321 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2008-2015 Emmanuel Dupuy
|
||||||
|
* This program is made available under the terms of the GPLv3 License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package jd.gui.service.indexer;
|
||||||
|
|
||||||
|
import jd.gui.api.API;
|
||||||
|
import jd.gui.api.model.Container;
|
||||||
|
import jd.gui.api.model.Indexes;
|
||||||
|
import jd.gui.util.parser.antlr.ANTLRParser;
|
||||||
|
import jd.gui.util.parser.antlr.AbstractJavaListener;
|
||||||
|
import jd.gui.util.parser.antlr.JavaParser;
|
||||||
|
import org.antlr.v4.runtime.ANTLRInputStream;
|
||||||
|
import org.antlr.v4.runtime.ParserRuleContext;
|
||||||
|
import org.antlr.v4.runtime.tree.ParseTree;
|
||||||
|
import org.antlr.v4.runtime.tree.TerminalNode;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unsafe thread implementation of java file indexer.
|
||||||
|
*/
|
||||||
|
public class JavaFileIndexerProvider extends AbstractIndexerProvider {
|
||||||
|
|
||||||
|
static {
|
||||||
|
// Early class loading
|
||||||
|
ANTLRParser.parse(new ANTLRInputStream("class EarlyLoading{}"), new Listener(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return local + optional external selectors
|
||||||
|
*/
|
||||||
|
public String[] getSelectors() {
|
||||||
|
List<String> externalSelectors = getExternalSelectors();
|
||||||
|
|
||||||
|
if (externalSelectors == null) {
|
||||||
|
return new String[] { "*:file:*.java" };
|
||||||
|
} else {
|
||||||
|
int size = externalSelectors.size();
|
||||||
|
String[] selectors = new String[size+1];
|
||||||
|
externalSelectors.toArray(selectors);
|
||||||
|
selectors[size] = "*:file:*.java";
|
||||||
|
return selectors;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Index format : @see jd.gui.spi.Indexer
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public void index(API api, Container.Entry entry, Indexes indexes) {
|
||||||
|
try (InputStream inputStream = entry.getInputStream()) {
|
||||||
|
Listener listener = new Listener(entry);
|
||||||
|
ANTLRParser.parse(new ANTLRInputStream(inputStream), listener);
|
||||||
|
|
||||||
|
// Append sets to indexes
|
||||||
|
addToIndex(indexes, "typeDeclarations", listener.getTypeDeclarationSet(), entry);
|
||||||
|
addToIndex(indexes, "constructorDeclarations", listener.getConstructorDeclarationSet(), entry);
|
||||||
|
addToIndex(indexes, "methodDeclarations", listener.getMethodDeclarationSet(), entry);
|
||||||
|
addToIndex(indexes, "fieldDeclarations", listener.getFieldDeclarationSet(), entry);
|
||||||
|
addToIndex(indexes, "typeReferences", listener.getTypeReferenceSet(), entry);
|
||||||
|
addToIndex(indexes, "constructorReferences", listener.getConstructorReferenceSet(), entry);
|
||||||
|
addToIndex(indexes, "methodReferences", listener.getMethodReferenceSet(), entry);
|
||||||
|
addToIndex(indexes, "fieldReferences", listener.getFieldReferenceSet(), entry);
|
||||||
|
addToIndex(indexes, "strings", listener.getStringSet(), entry);
|
||||||
|
|
||||||
|
// Populate map [super type name : [sub type name]]
|
||||||
|
Map<String, Collection> index = indexes.getIndex("subTypeNames");
|
||||||
|
|
||||||
|
for (Map.Entry<String, HashSet<String>> e : listener.getSuperTypeNamesMap().entrySet()) {
|
||||||
|
String typeName = e.getKey();
|
||||||
|
|
||||||
|
for (String superTypeName : e.getValue()) {
|
||||||
|
index.get(superTypeName).add(typeName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException ignore) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static class Listener extends AbstractJavaListener {
|
||||||
|
|
||||||
|
protected HashSet<String> typeDeclarationSet = new HashSet<>();
|
||||||
|
protected HashSet<String> constructorDeclarationSet = new HashSet<>();
|
||||||
|
protected HashSet<String> methodDeclarationSet = new HashSet<>();
|
||||||
|
protected HashSet<String> fieldDeclarationSet = new HashSet<>();
|
||||||
|
protected HashSet<String> typeReferenceSet = new HashSet<>();
|
||||||
|
protected HashSet<String> constructorReferenceSet = new HashSet<>();
|
||||||
|
protected HashSet<String> methodReferenceSet = new HashSet<>();
|
||||||
|
protected HashSet<String> fieldReferenceSet = new HashSet<>();
|
||||||
|
protected HashSet<String> stringSet = new HashSet<>();
|
||||||
|
protected HashMap<String, HashSet<String>> superTypeNamesMap = new HashMap<>();
|
||||||
|
|
||||||
|
protected StringBuffer sbTypeDeclaration = new StringBuffer();
|
||||||
|
|
||||||
|
public Listener(Container.Entry entry) {
|
||||||
|
super(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
public HashSet<String> getTypeDeclarationSet() { return typeDeclarationSet; }
|
||||||
|
public HashSet<String> getConstructorDeclarationSet() { return constructorDeclarationSet; }
|
||||||
|
public HashSet<String> getMethodDeclarationSet() { return methodDeclarationSet; }
|
||||||
|
public HashSet<String> getFieldDeclarationSet() { return fieldDeclarationSet; }
|
||||||
|
public HashSet<String> getTypeReferenceSet() { return typeReferenceSet; }
|
||||||
|
public HashSet<String> getConstructorReferenceSet() { return constructorReferenceSet; }
|
||||||
|
public HashSet<String> getMethodReferenceSet() { return methodReferenceSet; }
|
||||||
|
public HashSet<String> getFieldReferenceSet() { return fieldReferenceSet; }
|
||||||
|
public HashSet<String> getStringSet() { return stringSet; }
|
||||||
|
public HashMap<String, HashSet<String>> getSuperTypeNamesMap() { return superTypeNamesMap; }
|
||||||
|
|
||||||
|
// --- ANTLR Listener --- //
|
||||||
|
|
||||||
|
public void enterPackageDeclaration(JavaParser.PackageDeclarationContext ctx) {
|
||||||
|
super.enterPackageDeclaration(ctx);
|
||||||
|
|
||||||
|
if (! packageName.isEmpty()) {
|
||||||
|
sbTypeDeclaration.append(packageName).append('/');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void enterClassDeclaration(JavaParser.ClassDeclarationContext ctx) { enterTypeDeclaration(ctx); }
|
||||||
|
public void exitClassDeclaration(JavaParser.ClassDeclarationContext ctx) { exitTypeDeclaration(); }
|
||||||
|
|
||||||
|
public void enterEnumDeclaration(JavaParser.EnumDeclarationContext ctx) { enterTypeDeclaration(ctx); }
|
||||||
|
public void exitEnumDeclaration(JavaParser.EnumDeclarationContext ctx) { exitTypeDeclaration(); }
|
||||||
|
|
||||||
|
public void enterInterfaceDeclaration(JavaParser.InterfaceDeclarationContext ctx) { enterTypeDeclaration(ctx); }
|
||||||
|
public void exitInterfaceDeclaration(JavaParser.InterfaceDeclarationContext ctx) { exitTypeDeclaration(); }
|
||||||
|
|
||||||
|
public void enterAnnotationTypeDeclaration(JavaParser.AnnotationTypeDeclarationContext ctx) { enterTypeDeclaration(ctx); }
|
||||||
|
public void exitAnnotationTypeDeclaration(JavaParser.AnnotationTypeDeclarationContext ctx) { exitTypeDeclaration(); }
|
||||||
|
|
||||||
|
protected void enterTypeDeclaration(ParserRuleContext ctx) {
|
||||||
|
// Add type declaration
|
||||||
|
String typeName = ctx.getToken(JavaParser.Identifier, 0).getText();
|
||||||
|
int length = sbTypeDeclaration.length();
|
||||||
|
|
||||||
|
if ((length == 0) || (sbTypeDeclaration.charAt(length-1) == '/')) {
|
||||||
|
sbTypeDeclaration.append(typeName);
|
||||||
|
} else {
|
||||||
|
sbTypeDeclaration.append('$').append(typeName);
|
||||||
|
}
|
||||||
|
|
||||||
|
String internalTypeName = sbTypeDeclaration.toString();
|
||||||
|
typeDeclarationSet.add(internalTypeName);
|
||||||
|
nameToInternalTypeName.put(typeName, internalTypeName);
|
||||||
|
|
||||||
|
HashSet<String> superInternalTypeNameSet = new HashSet<>();
|
||||||
|
|
||||||
|
// Add super type reference
|
||||||
|
JavaParser.TypeContext superType = ctx.getRuleContext(JavaParser.TypeContext.class, 0);
|
||||||
|
if (superType != null) {
|
||||||
|
String superQualifiedTypeName = resolveInternalTypeName(superType.classOrInterfaceType().Identifier());
|
||||||
|
|
||||||
|
if (superQualifiedTypeName.charAt(0) != '*')
|
||||||
|
superInternalTypeNameSet.add(superQualifiedTypeName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add implementation references
|
||||||
|
JavaParser.TypeListContext superInterfaces = ctx.getRuleContext(JavaParser.TypeListContext.class, 0);
|
||||||
|
if (superInterfaces != null) {
|
||||||
|
for (JavaParser.TypeContext superInterface : superInterfaces.type()) {
|
||||||
|
String superQualifiedInterfaceName = resolveInternalTypeName(superInterface.classOrInterfaceType().Identifier());
|
||||||
|
|
||||||
|
if (superQualifiedInterfaceName.charAt(0) != '*')
|
||||||
|
superInternalTypeNameSet.add(superQualifiedInterfaceName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! superInternalTypeNameSet.isEmpty()) {
|
||||||
|
superTypeNamesMap.put(internalTypeName, superInternalTypeNameSet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void exitTypeDeclaration() {
|
||||||
|
int index = sbTypeDeclaration.lastIndexOf("$");
|
||||||
|
|
||||||
|
if (index == -1) {
|
||||||
|
index = sbTypeDeclaration.lastIndexOf("/") + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index == -1) {
|
||||||
|
sbTypeDeclaration.setLength(0);
|
||||||
|
} else {
|
||||||
|
sbTypeDeclaration.setLength(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void enterType(JavaParser.TypeContext ctx) {
|
||||||
|
// Add type reference
|
||||||
|
JavaParser.ClassOrInterfaceTypeContext classOrInterfaceType = ctx.classOrInterfaceType();
|
||||||
|
|
||||||
|
if (classOrInterfaceType != null) {
|
||||||
|
String internalTypeName = resolveInternalTypeName(classOrInterfaceType.Identifier());
|
||||||
|
|
||||||
|
if (internalTypeName.charAt(0) != '*')
|
||||||
|
typeReferenceSet.add(internalTypeName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void enterConstDeclaration(JavaParser.ConstDeclarationContext ctx) {
|
||||||
|
for (JavaParser.ConstantDeclaratorContext constantDeclaratorContext : ctx.constantDeclarator()) {
|
||||||
|
String name = constantDeclaratorContext.Identifier().getText();
|
||||||
|
fieldDeclarationSet.add(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void enterFieldDeclaration(JavaParser.FieldDeclarationContext ctx) {
|
||||||
|
for (JavaParser.VariableDeclaratorContext declaration : ctx.variableDeclarators().variableDeclarator()) {
|
||||||
|
String name = declaration.variableDeclaratorId().Identifier().getText();
|
||||||
|
fieldDeclarationSet.add(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void enterMethodDeclaration(JavaParser.MethodDeclarationContext ctx) {
|
||||||
|
String name = ctx.Identifier().getText();
|
||||||
|
methodDeclarationSet.add(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void enterInterfaceMethodDeclaration(JavaParser.InterfaceMethodDeclarationContext ctx) {
|
||||||
|
String name = ctx.Identifier().getText();
|
||||||
|
methodDeclarationSet.add(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void enterConstructorDeclaration(JavaParser.ConstructorDeclarationContext ctx) {
|
||||||
|
String name = ctx.Identifier().getText();
|
||||||
|
constructorDeclarationSet.add(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void enterCreatedName(JavaParser.CreatedNameContext ctx) {
|
||||||
|
String internalTypeName = resolveInternalTypeName(ctx.Identifier());
|
||||||
|
|
||||||
|
if ((internalTypeName != null) && (internalTypeName.charAt(0) != '*'))
|
||||||
|
constructorReferenceSet.add(internalTypeName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void enterExpression(JavaParser.ExpressionContext ctx) {
|
||||||
|
switch (ctx.getChildCount()) {
|
||||||
|
case 3:
|
||||||
|
if (getToken(ctx.children, 1, JavaParser.DOT) != null) {
|
||||||
|
// Search "expression '.' Identifier" : field
|
||||||
|
TerminalNode identifier3 = getToken(ctx.children, 2, JavaParser.Identifier);
|
||||||
|
|
||||||
|
if (identifier3 != null) {
|
||||||
|
String fieldName = identifier3.getText();
|
||||||
|
fieldReferenceSet.add(fieldName);
|
||||||
|
}
|
||||||
|
} else if (getToken(ctx.children, 1, JavaParser.LPAREN) != null) {
|
||||||
|
// Search "expression '(' ')'" : method
|
||||||
|
if (getToken(ctx.children, 2, JavaParser.RPAREN) != null) {
|
||||||
|
TerminalNode identifier0 = getRightTerminalNode(ctx.children.get(0));
|
||||||
|
|
||||||
|
if (identifier0 != null) {
|
||||||
|
String methodName = identifier0.getText();
|
||||||
|
methodReferenceSet.add(methodName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
if (getToken(ctx.children, 1, JavaParser.LPAREN) != null) {
|
||||||
|
// Search "expression '(' expressionList ')'" : method
|
||||||
|
if (getToken(ctx.children, 3, JavaParser.RPAREN) != null) {
|
||||||
|
JavaParser.ExpressionListContext expressionListContext = ctx.expressionList();
|
||||||
|
|
||||||
|
if ((expressionListContext != null) && (expressionListContext == ctx.children.get(2))) {
|
||||||
|
TerminalNode identifier0 = getRightTerminalNode(ctx.children.get(0));
|
||||||
|
|
||||||
|
if (identifier0 != null) {
|
||||||
|
String methodName = identifier0.getText();
|
||||||
|
methodReferenceSet.add(methodName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected TerminalNode getToken(List<ParseTree> children, int i, int type) {
|
||||||
|
ParseTree pt = children.get(i);
|
||||||
|
|
||||||
|
if (pt instanceof TerminalNode) {
|
||||||
|
if (((TerminalNode)pt).getSymbol().getType() == type) {
|
||||||
|
return (TerminalNode)pt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected TerminalNode getRightTerminalNode(ParseTree pt) {
|
||||||
|
if (pt instanceof ParserRuleContext) {
|
||||||
|
List<ParseTree> children = ((ParserRuleContext)pt).children;
|
||||||
|
int size = children.size();
|
||||||
|
|
||||||
|
if (size > 0) {
|
||||||
|
ParseTree last = children.get(size - 1);
|
||||||
|
|
||||||
|
if (last instanceof TerminalNode) {
|
||||||
|
return (TerminalNode) last;
|
||||||
|
} else {
|
||||||
|
return getRightTerminalNode(last);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void enterLiteral(JavaParser.LiteralContext ctx) {
|
||||||
|
TerminalNode stringLiteral = ctx.StringLiteral();
|
||||||
|
if (stringLiteral != null) {
|
||||||
|
stringSet.add(stringLiteral.getSymbol().getText());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -5,8 +5,12 @@
|
|||||||
|
|
||||||
package jd.gui.service.type;
|
package jd.gui.service.type;
|
||||||
|
|
||||||
|
import jd.gui.api.model.Type;
|
||||||
import jd.gui.spi.TypeFactory;
|
import jd.gui.spi.TypeFactory;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@ -22,7 +26,7 @@ public abstract class AbstractTypeFactoryProvider implements TypeFactory {
|
|||||||
/**
|
/**
|
||||||
* Initialize "selectors" and "pathPattern" with optional external properties file
|
* Initialize "selectors" and "pathPattern" with optional external properties file
|
||||||
*/
|
*/
|
||||||
AbstractTypeFactoryProvider() {
|
public AbstractTypeFactoryProvider() {
|
||||||
Properties properties = new Properties();
|
Properties properties = new Properties();
|
||||||
Class clazz = this.getClass();
|
Class clazz = this.getClass();
|
||||||
|
|
||||||
@ -51,4 +55,153 @@ public abstract class AbstractTypeFactoryProvider implements TypeFactory {
|
|||||||
return (externalSelectors==null) ? null : externalSelectors.toArray(new String[externalSelectors.size()]);
|
return (externalSelectors==null) ? null : externalSelectors.toArray(new String[externalSelectors.size()]);
|
||||||
}
|
}
|
||||||
public Pattern getPathPattern() { return externalPathPattern; }
|
public Pattern getPathPattern() { return externalPathPattern; }
|
||||||
|
|
||||||
|
protected static ImageIcon getTypeIcon(int access) {
|
||||||
|
if ((access & Type.FLAG_ANNOTATION) != 0)
|
||||||
|
return ANNOTATION_ICON;
|
||||||
|
else if ((access & Type.FLAG_INTERFACE) != 0)
|
||||||
|
return INTERFACE_ICONS[accessToIndex(access)];
|
||||||
|
else if ((access & Type.FLAG_ENUM) != 0)
|
||||||
|
return ENUM_ICON;
|
||||||
|
else
|
||||||
|
return CLASS_ICONS[accessToIndex(access)];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static ImageIcon getFieldIcon(int access) {
|
||||||
|
return FIELD_ICONS[accessToIndex(access)];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static ImageIcon getMethodIcon(int access) {
|
||||||
|
return METHOD_ICONS[accessToIndex(access)];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static int accessToIndex(int access) {
|
||||||
|
int index = 0;
|
||||||
|
|
||||||
|
if ((access & Type.FLAG_STATIC) != 0)
|
||||||
|
index += 4;
|
||||||
|
|
||||||
|
if ((access & Type.FLAG_FINAL) != 0)
|
||||||
|
index += 8;
|
||||||
|
|
||||||
|
if ((access & Type.FLAG_ABSTRACT) != 0)
|
||||||
|
index += 16;
|
||||||
|
|
||||||
|
if ((access & Type.FLAG_PUBLIC) != 0)
|
||||||
|
return index + 1;
|
||||||
|
else if ((access & Type.FLAG_PROTECTED) != 0)
|
||||||
|
return index + 2;
|
||||||
|
else if ((access & Type.FLAG_PRIVATE) != 0)
|
||||||
|
return index + 3;
|
||||||
|
else
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Graphic stuff ...
|
||||||
|
protected static ImageIcon mergeIcons(ImageIcon background, ImageIcon overlay, int x, int y) {
|
||||||
|
int w = background.getIconWidth();
|
||||||
|
int h = background.getIconHeight();
|
||||||
|
BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
|
||||||
|
|
||||||
|
if (x + overlay.getIconWidth() > w)
|
||||||
|
x = w - overlay.getIconWidth();
|
||||||
|
if (y + overlay.getIconHeight() > h)
|
||||||
|
y = h - overlay.getIconHeight();
|
||||||
|
|
||||||
|
Graphics2D g2 = image.createGraphics();
|
||||||
|
g2.drawImage(background.getImage(), 0, 0, null);
|
||||||
|
g2.drawImage(overlay.getImage(), x, y, null);
|
||||||
|
g2.dispose();
|
||||||
|
|
||||||
|
return new ImageIcon(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static ImageIcon[] mergeIcons(ImageIcon[] backgrounds, ImageIcon overlay, int x, int y) {
|
||||||
|
int length = backgrounds.length;
|
||||||
|
ImageIcon[] result = new ImageIcon[length*2];
|
||||||
|
|
||||||
|
// Copy source icons
|
||||||
|
System.arraycopy(backgrounds, 0, result, 0, length);
|
||||||
|
|
||||||
|
// Add overlays
|
||||||
|
for (int i=0; i<length; i++) {
|
||||||
|
result[length+i] = mergeIcons(backgrounds[i], overlay, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static final ImageIcon ABSTRACT_OVERLAY_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/abstract_ovr.png"));
|
||||||
|
protected static final ImageIcon FINAL_OVERLAY_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/final_ovr.png"));
|
||||||
|
protected static final ImageIcon STATIC_OVERLAY_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/static_ovr.png"));
|
||||||
|
|
||||||
|
protected static final ImageIcon CLASS_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/class_default_obj.png"));
|
||||||
|
protected static final ImageIcon PUBLIC_CLASS_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/class_obj.png"));
|
||||||
|
protected static final ImageIcon PROTECTED_CLASS_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/class_protected_obj.png"));
|
||||||
|
protected static final ImageIcon PRIVATE_CLASS_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/class_private_obj.png"));
|
||||||
|
|
||||||
|
protected static final ImageIcon INTERFACE_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/int_default_obj.png"));
|
||||||
|
protected static final ImageIcon PUBLIC_INTERFACE_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/int_obj.png"));
|
||||||
|
protected static final ImageIcon PROTECTED_INTERFACE_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/int_protected_obj.png"));
|
||||||
|
protected static final ImageIcon PRIVATE_INTERFACE_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/int_private_obj.png"));
|
||||||
|
|
||||||
|
protected static final ImageIcon ANNOTATION_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/annotation_obj.png"));
|
||||||
|
protected static final ImageIcon ENUM_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/enum_obj.png"));
|
||||||
|
|
||||||
|
protected static final ImageIcon FIELD_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/field_default_obj.png"));
|
||||||
|
protected static final ImageIcon PUBLIC_FIELD_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/field_public_obj.png"));
|
||||||
|
protected static final ImageIcon PROTECTED_FIELD_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/field_protected_obj.png"));
|
||||||
|
protected static final ImageIcon PRIVATE_FIELD_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/field_private_obj.png"));
|
||||||
|
|
||||||
|
protected static final ImageIcon METHOD_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/methdef_obj.png"));
|
||||||
|
protected static final ImageIcon PUBLIC_METHOD_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/methpub_obj.png"));
|
||||||
|
protected static final ImageIcon PROTECTED_METHOD_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/methpro_obj.png"));
|
||||||
|
protected static final ImageIcon PRIVATE_METHOD_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/methpri_obj.png"));
|
||||||
|
|
||||||
|
// Default icon set
|
||||||
|
protected static final ImageIcon[] DEFAULT_CLASS_ICONS = {
|
||||||
|
CLASS_ICON,
|
||||||
|
PUBLIC_CLASS_ICON,
|
||||||
|
PROTECTED_CLASS_ICON,
|
||||||
|
PRIVATE_CLASS_ICON
|
||||||
|
};
|
||||||
|
|
||||||
|
protected static final ImageIcon[] DEFAULT_INTERFACE_ICONS = {
|
||||||
|
INTERFACE_ICON,
|
||||||
|
PUBLIC_INTERFACE_ICON,
|
||||||
|
PROTECTED_INTERFACE_ICON,
|
||||||
|
PRIVATE_INTERFACE_ICON
|
||||||
|
};
|
||||||
|
|
||||||
|
protected static final ImageIcon[] DEFAULT_FIELD_ICONS = {
|
||||||
|
FIELD_ICON,
|
||||||
|
PUBLIC_FIELD_ICON,
|
||||||
|
PROTECTED_FIELD_ICON,
|
||||||
|
PRIVATE_FIELD_ICON
|
||||||
|
};
|
||||||
|
|
||||||
|
protected static final ImageIcon[] DEFAULT_METHOD_ICONS = {
|
||||||
|
METHOD_ICON,
|
||||||
|
PUBLIC_METHOD_ICON,
|
||||||
|
PROTECTED_METHOD_ICON,
|
||||||
|
PRIVATE_METHOD_ICON
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add static icon set
|
||||||
|
protected static final ImageIcon[] STATIC_CLASS_ICONS = mergeIcons(DEFAULT_CLASS_ICONS, STATIC_OVERLAY_ICON, 100, 0);
|
||||||
|
protected static final ImageIcon[] STATIC_INTERFACE_ICONS = mergeIcons(DEFAULT_INTERFACE_ICONS, STATIC_OVERLAY_ICON, 100, 0);
|
||||||
|
protected static final ImageIcon[] STATIC_FIELD_ICONS = mergeIcons(DEFAULT_FIELD_ICONS, STATIC_OVERLAY_ICON, 100, 0);
|
||||||
|
protected static final ImageIcon[] STATIC_METHOD_ICONS = mergeIcons(DEFAULT_METHOD_ICONS, STATIC_OVERLAY_ICON, 100, 0);
|
||||||
|
|
||||||
|
// Add final icon set
|
||||||
|
protected static final ImageIcon[] FINAL_STATIC_CLASS_ICONS = mergeIcons(STATIC_CLASS_ICONS, FINAL_OVERLAY_ICON, 0, 0);
|
||||||
|
protected static final ImageIcon[] FINAL_STATIC_INTERFACE_ICONS = mergeIcons(STATIC_INTERFACE_ICONS, FINAL_OVERLAY_ICON, 0, 0);
|
||||||
|
protected static final ImageIcon[] FINAL_STATIC_FIELD_ICONS = mergeIcons(STATIC_FIELD_ICONS, FINAL_OVERLAY_ICON, 0, 0);
|
||||||
|
protected static final ImageIcon[] FINAL_STATIC_METHOD_ICONS = mergeIcons(STATIC_METHOD_ICONS, FINAL_OVERLAY_ICON, 0, 0);
|
||||||
|
|
||||||
|
// Add abstract icon set
|
||||||
|
protected static final ImageIcon[] CLASS_ICONS = mergeIcons(FINAL_STATIC_CLASS_ICONS, ABSTRACT_OVERLAY_ICON, 0, 100);
|
||||||
|
protected static final ImageIcon[] INTERFACE_ICONS = mergeIcons(FINAL_STATIC_INTERFACE_ICONS, ABSTRACT_OVERLAY_ICON, 0, 100);
|
||||||
|
protected static final ImageIcon[] FIELD_ICONS = mergeIcons(FINAL_STATIC_FIELD_ICONS, ABSTRACT_OVERLAY_ICON, 0, 100);
|
||||||
|
protected static final ImageIcon[] METHOD_ICONS = mergeIcons(FINAL_STATIC_METHOD_ICONS, ABSTRACT_OVERLAY_ICON, 0, 100);
|
||||||
}
|
}
|
||||||
|
@ -16,11 +16,11 @@ import jd.gui.api.model.Container;
|
|||||||
import jd.gui.api.model.Type;
|
import jd.gui.api.model.Type;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import java.awt.*;
|
|
||||||
import java.awt.image.BufferedImage;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class ClassFileTypeFactoryProvider extends AbstractTypeFactoryProvider {
|
public class ClassFileTypeFactoryProvider extends AbstractTypeFactoryProvider {
|
||||||
@ -47,6 +47,10 @@ public class ClassFileTypeFactoryProvider extends AbstractTypeFactoryProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Collection<Type> make(API api, Container.Entry entry) {
|
||||||
|
return Collections.singletonList(make(api, entry, null));
|
||||||
|
}
|
||||||
|
|
||||||
public Type make(API api, Container.Entry entry, String fragment) {
|
public Type make(API api, Container.Entry entry, String fragment) {
|
||||||
try (InputStream is = entry.getInputStream()) {
|
try (InputStream is = entry.getInputStream()) {
|
||||||
ClassReader classReader = new ClassReader(is);
|
ClassReader classReader = new ClassReader(is);
|
||||||
@ -110,24 +114,24 @@ public class ClassFileTypeFactoryProvider extends AbstractTypeFactoryProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static class JavaType implements Type {
|
static class JavaType implements Type {
|
||||||
ClassNode classNode;
|
|
||||||
Container.Entry entry;
|
|
||||||
int access;
|
|
||||||
String name;
|
|
||||||
String shortName;
|
|
||||||
String superName;
|
|
||||||
String outerName;
|
|
||||||
|
|
||||||
String displayTypeName;
|
protected ClassNode classNode;
|
||||||
String displayInnerTypeName;
|
protected Container.Entry entry;
|
||||||
String displayPackageName;
|
protected int access;
|
||||||
|
protected String name;
|
||||||
|
protected String superName;
|
||||||
|
protected String outerName;
|
||||||
|
|
||||||
List<Type> innerTypes;
|
protected String displayTypeName;
|
||||||
List<Type.Field> fields;
|
protected String displayInnerTypeName;
|
||||||
List<Type.Method> methods;
|
protected String displayPackageName;
|
||||||
|
|
||||||
|
protected List<Type> innerTypes = null;
|
||||||
|
protected List<Type.Field> fields = null;
|
||||||
|
protected List<Type.Method> methods = null;
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
JavaType(Container.Entry entry, ClassReader classReader) {
|
protected JavaType(Container.Entry entry, ClassReader classReader) {
|
||||||
this.classNode = new ClassNode();
|
this.classNode = new ClassNode();
|
||||||
this.entry = entry;
|
this.entry = entry;
|
||||||
|
|
||||||
@ -161,27 +165,17 @@ public class ClassFileTypeFactoryProvider extends AbstractTypeFactoryProvider {
|
|||||||
|
|
||||||
if (lastPackageSeparatorIndex == -1) {
|
if (lastPackageSeparatorIndex == -1) {
|
||||||
this.displayPackageName = "";
|
this.displayPackageName = "";
|
||||||
this.shortName = this.name;
|
this.displayTypeName = (this.outerName == null) ? this.name : null;
|
||||||
this.displayTypeName = (this.outerName != null) ? null : this.shortName;
|
|
||||||
} else {
|
} else {
|
||||||
this.displayPackageName = this.name.substring(0, lastPackageSeparatorIndex).replace('/', '.');
|
this.displayPackageName = this.name.substring(0, lastPackageSeparatorIndex).replace('/', '.');
|
||||||
this.shortName = this.name.substring(lastPackageSeparatorIndex+1);
|
this.displayTypeName = (this.outerName == null) ? this.name.substring(lastPackageSeparatorIndex+1) : null;
|
||||||
this.displayTypeName = (this.outerName != null) ? null : this.shortName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.innerTypes = null;
|
|
||||||
this.fields = null;
|
|
||||||
this.methods = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getFlags() { return access; }
|
public int getFlags() { return access; }
|
||||||
public String getName() { return name; }
|
public String getName() { return name; }
|
||||||
public String getShortName() { return shortName; }
|
|
||||||
public String getSuperName() { return superName; }
|
public String getSuperName() { return superName; }
|
||||||
public String getOuterName() { return outerName; }
|
public String getOuterName() { return outerName; }
|
||||||
|
|
||||||
public Container.Entry getOuterEntry() { return (outerName==null) ? null : getEntry(outerName); }
|
|
||||||
|
|
||||||
public String getDisplayPackageName() { return displayPackageName; }
|
public String getDisplayPackageName() { return displayPackageName; }
|
||||||
|
|
||||||
public String getDisplayTypeName() {
|
public String getDisplayTypeName() {
|
||||||
@ -219,7 +213,7 @@ public class ClassFileTypeFactoryProvider extends AbstractTypeFactoryProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String getDisplayInnerTypeName() { return displayInnerTypeName; }
|
public String getDisplayInnerTypeName() { return displayInnerTypeName; }
|
||||||
public Icon getIcon() { return getIcon(access); }
|
public Icon getIcon() { return getTypeIcon(access); }
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public List<Type> getInnerTypes() {
|
public List<Type> getInnerTypes() {
|
||||||
@ -266,7 +260,7 @@ public class ClassFileTypeFactoryProvider extends AbstractTypeFactoryProvider {
|
|||||||
public int getFlags() { return fieldNode.access; }
|
public int getFlags() { return fieldNode.access; }
|
||||||
public String getName() { return fieldNode.name; }
|
public String getName() { return fieldNode.name; }
|
||||||
public String getDescriptor() { return fieldNode.desc; }
|
public String getDescriptor() { return fieldNode.desc; }
|
||||||
public Icon getIcon() { return FIELD_ICONS[accessToIndex(fieldNode.access)]; }
|
public Icon getIcon() { return getFieldIcon(fieldNode.access); }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -285,153 +279,13 @@ public class ClassFileTypeFactoryProvider extends AbstractTypeFactoryProvider {
|
|||||||
public int getFlags() { return methodNode.access; }
|
public int getFlags() { return methodNode.access; }
|
||||||
public String getName() { return methodNode.name; }
|
public String getName() { return methodNode.name; }
|
||||||
public String getDescriptor() { return methodNode.desc; }
|
public String getDescriptor() { return methodNode.desc; }
|
||||||
public Icon getIcon() { return METHOD_ICONS[accessToIndex(methodNode.access)]; }
|
public Icon getIcon() { return getMethodIcon(methodNode.access); }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return methods;
|
return methods;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static ImageIcon getIcon(int access) {
|
|
||||||
if ((access & Opcodes.ACC_ANNOTATION) != 0)
|
|
||||||
return ANNOTATION_ICON;
|
|
||||||
else if ((access & Opcodes.ACC_INTERFACE) != 0)
|
|
||||||
return INTERFACE_ICONS[accessToIndex(access)];
|
|
||||||
else if ((access & Opcodes.ACC_ENUM) != 0)
|
|
||||||
return ENUM_ICON;
|
|
||||||
else
|
|
||||||
return CLASS_ICONS[accessToIndex(access)];
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static int accessToIndex(int access) {
|
|
||||||
int index = 0;
|
|
||||||
|
|
||||||
if ((access & Opcodes.ACC_STATIC) != 0)
|
|
||||||
index += 4;
|
|
||||||
|
|
||||||
if ((access & Opcodes.ACC_FINAL) != 0)
|
|
||||||
index += 8;
|
|
||||||
|
|
||||||
if ((access & Opcodes.ACC_ABSTRACT) != 0)
|
|
||||||
index += 16;
|
|
||||||
|
|
||||||
if ((access & Opcodes.ACC_PUBLIC) != 0)
|
|
||||||
return index + 1;
|
|
||||||
else if ((access & Opcodes.ACC_PROTECTED) != 0)
|
|
||||||
return index + 2;
|
|
||||||
else if ((access & Opcodes.ACC_PRIVATE) != 0)
|
|
||||||
return index + 3;
|
|
||||||
else
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Graphic stuff ...
|
|
||||||
protected static ImageIcon mergeIcons(ImageIcon background, ImageIcon overlay, int x, int y) {
|
|
||||||
int w = background.getIconWidth();
|
|
||||||
int h = background.getIconHeight();
|
|
||||||
BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
|
|
||||||
|
|
||||||
if (x + overlay.getIconWidth() > w)
|
|
||||||
x = w - overlay.getIconWidth();
|
|
||||||
if (y + overlay.getIconHeight() > h)
|
|
||||||
y = h - overlay.getIconHeight();
|
|
||||||
|
|
||||||
Graphics2D g2 = image.createGraphics();
|
|
||||||
g2.drawImage(background.getImage(), 0, 0, null);
|
|
||||||
g2.drawImage(overlay.getImage(), x, y, null);
|
|
||||||
g2.dispose();
|
|
||||||
|
|
||||||
return new ImageIcon(image);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static ImageIcon[] mergeIcons(ImageIcon[] backgrounds, ImageIcon overlay, int x, int y) {
|
|
||||||
int length = backgrounds.length;
|
|
||||||
ImageIcon[] result = new ImageIcon[length*2];
|
|
||||||
|
|
||||||
// Copy source icons
|
|
||||||
System.arraycopy(backgrounds, 0, result, 0, length);
|
|
||||||
|
|
||||||
// Add overlays
|
|
||||||
for (int i=0; i<length; i++) {
|
|
||||||
result[length+i] = mergeIcons(backgrounds[i], overlay, x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static final ImageIcon ABSTRACT_OVERLAY_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/abstract_ovr.png"));
|
|
||||||
protected static final ImageIcon FINAL_OVERLAY_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/final_ovr.png"));
|
|
||||||
protected static final ImageIcon STATIC_OVERLAY_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/static_ovr.png"));
|
|
||||||
|
|
||||||
protected static final ImageIcon CLASS_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/class_default_obj.png"));
|
|
||||||
protected static final ImageIcon PUBLIC_CLASS_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/class_obj.png"));
|
|
||||||
protected static final ImageIcon PROTECTED_CLASS_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/class_protected_obj.png"));
|
|
||||||
protected static final ImageIcon PRIVATE_CLASS_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/class_private_obj.png"));
|
|
||||||
|
|
||||||
protected static final ImageIcon INTERFACE_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/int_default_obj.png"));
|
|
||||||
protected static final ImageIcon PUBLIC_INTERFACE_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/int_obj.png"));
|
|
||||||
protected static final ImageIcon PROTECTED_INTERFACE_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/int_protected_obj.png"));
|
|
||||||
protected static final ImageIcon PRIVATE_INTERFACE_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/int_private_obj.png"));
|
|
||||||
|
|
||||||
protected static final ImageIcon ANNOTATION_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/annotation_obj.png"));
|
|
||||||
protected static final ImageIcon ENUM_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/enum_obj.png"));
|
|
||||||
|
|
||||||
protected static final ImageIcon FIELD_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/field_default_obj.png"));
|
|
||||||
protected static final ImageIcon PUBLIC_FIELD_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/field_public_obj.png"));
|
|
||||||
protected static final ImageIcon PROTECTED_FIELD_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/field_protected_obj.png"));
|
|
||||||
protected static final ImageIcon PRIVATE_FIELD_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/field_private_obj.png"));
|
|
||||||
|
|
||||||
protected static final ImageIcon METHOD_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/methdef_obj.png"));
|
|
||||||
protected static final ImageIcon PUBLIC_METHOD_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/methpub_obj.png"));
|
|
||||||
protected static final ImageIcon PROTECTED_METHOD_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/methpro_obj.png"));
|
|
||||||
protected static final ImageIcon PRIVATE_METHOD_ICON = new ImageIcon(ClassFileTypeFactoryProvider.class.getClassLoader().getResource("images/methpri_obj.png"));
|
|
||||||
|
|
||||||
// Default icon set
|
|
||||||
protected static final ImageIcon[] DEFAULT_CLASS_ICONS = {
|
|
||||||
CLASS_ICON,
|
|
||||||
PUBLIC_CLASS_ICON,
|
|
||||||
PROTECTED_CLASS_ICON,
|
|
||||||
PRIVATE_CLASS_ICON
|
|
||||||
};
|
|
||||||
|
|
||||||
protected static final ImageIcon[] DEFAULT_INTERFACE_ICONS = {
|
|
||||||
INTERFACE_ICON,
|
|
||||||
PUBLIC_INTERFACE_ICON,
|
|
||||||
PROTECTED_INTERFACE_ICON,
|
|
||||||
PRIVATE_INTERFACE_ICON
|
|
||||||
};
|
|
||||||
|
|
||||||
protected static final ImageIcon[] DEFAULT_FIELD_ICONS = {
|
|
||||||
FIELD_ICON,
|
|
||||||
PUBLIC_FIELD_ICON,
|
|
||||||
PROTECTED_FIELD_ICON,
|
|
||||||
PRIVATE_FIELD_ICON
|
|
||||||
};
|
|
||||||
|
|
||||||
protected static final ImageIcon[] DEFAULT_METHOD_ICONS = {
|
|
||||||
METHOD_ICON,
|
|
||||||
PUBLIC_METHOD_ICON,
|
|
||||||
PROTECTED_METHOD_ICON,
|
|
||||||
PRIVATE_METHOD_ICON
|
|
||||||
};
|
|
||||||
|
|
||||||
// Add static icon set
|
|
||||||
protected static final ImageIcon[] STATIC_CLASS_ICONS = mergeIcons(DEFAULT_CLASS_ICONS, STATIC_OVERLAY_ICON, 100, 0);
|
|
||||||
protected static final ImageIcon[] STATIC_INTERFACE_ICONS = mergeIcons(DEFAULT_INTERFACE_ICONS, STATIC_OVERLAY_ICON, 100, 0);
|
|
||||||
protected static final ImageIcon[] STATIC_FIELD_ICONS = mergeIcons(DEFAULT_FIELD_ICONS, STATIC_OVERLAY_ICON, 100, 0);
|
|
||||||
protected static final ImageIcon[] STATIC_METHOD_ICONS = mergeIcons(DEFAULT_METHOD_ICONS, STATIC_OVERLAY_ICON, 100, 0);
|
|
||||||
|
|
||||||
// Add final icon set
|
|
||||||
protected static final ImageIcon[] FINAL_STATIC_CLASS_ICONS = mergeIcons(STATIC_CLASS_ICONS, FINAL_OVERLAY_ICON, 0, 0);
|
|
||||||
protected static final ImageIcon[] FINAL_STATIC_INTERFACE_ICONS = mergeIcons(STATIC_INTERFACE_ICONS, FINAL_OVERLAY_ICON, 0, 0);
|
|
||||||
protected static final ImageIcon[] FINAL_STATIC_FIELD_ICONS = mergeIcons(STATIC_FIELD_ICONS, FINAL_OVERLAY_ICON, 0, 0);
|
|
||||||
protected static final ImageIcon[] FINAL_STATIC_METHOD_ICONS = mergeIcons(STATIC_METHOD_ICONS, FINAL_OVERLAY_ICON, 0, 0);
|
|
||||||
|
|
||||||
// Add abstract icon set
|
|
||||||
protected static final ImageIcon[] CLASS_ICONS = mergeIcons(FINAL_STATIC_CLASS_ICONS, ABSTRACT_OVERLAY_ICON, 0, 100);
|
|
||||||
protected static final ImageIcon[] INTERFACE_ICONS = mergeIcons(FINAL_STATIC_INTERFACE_ICONS, ABSTRACT_OVERLAY_ICON, 0, 100);
|
|
||||||
protected static final ImageIcon[] FIELD_ICONS = mergeIcons(FINAL_STATIC_FIELD_ICONS, ABSTRACT_OVERLAY_ICON, 0, 100);
|
|
||||||
protected static final ImageIcon[] METHOD_ICONS = mergeIcons(FINAL_STATIC_METHOD_ICONS, ABSTRACT_OVERLAY_ICON, 0, 100);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,387 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2008-2015 Emmanuel Dupuy
|
||||||
|
* This program is made available under the terms of the GPLv3 License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package jd.gui.service.type;
|
||||||
|
|
||||||
|
import jd.gui.api.API;
|
||||||
|
import jd.gui.api.model.Container;
|
||||||
|
import jd.gui.api.model.Type;
|
||||||
|
import jd.gui.util.parser.antlr.*;
|
||||||
|
import org.antlr.v4.runtime.ANTLRInputStream;
|
||||||
|
import org.antlr.v4.runtime.ParserRuleContext;
|
||||||
|
import org.antlr.v4.runtime.tree.ParseTree;
|
||||||
|
import org.antlr.v4.runtime.tree.TerminalNode;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class JavaFileTypeFactoryProvider extends AbstractTypeFactoryProvider {
|
||||||
|
|
||||||
|
static {
|
||||||
|
// Early class loading
|
||||||
|
ANTLRParser.parse(new ANTLRInputStream("class EarlyLoading{}"), new Listener(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return local + optional external selectors
|
||||||
|
*/
|
||||||
|
public String[] getSelectors() {
|
||||||
|
List<String> externalSelectors = getExternalSelectors();
|
||||||
|
|
||||||
|
if (externalSelectors == null) {
|
||||||
|
return new String[] { "*:file:*.java" };
|
||||||
|
} else {
|
||||||
|
int size = externalSelectors.size();
|
||||||
|
String[] selectors = new String[size+1];
|
||||||
|
externalSelectors.toArray(selectors);
|
||||||
|
selectors[size] = "*:file:*.java";
|
||||||
|
return selectors;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<Type> make(API api, Container.Entry entry) {
|
||||||
|
try (InputStream inputStream = entry.getInputStream()) {
|
||||||
|
Listener listener = new Listener(entry);
|
||||||
|
ANTLRParser.parse(new ANTLRInputStream(inputStream), listener);
|
||||||
|
|
||||||
|
return listener.getRootTypes();
|
||||||
|
} catch (IOException ignore) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type make(API api, Container.Entry entry, String fragment) {
|
||||||
|
try (InputStream inputStream = entry.getInputStream()) {
|
||||||
|
Listener listener = new Listener(entry);
|
||||||
|
ANTLRParser.parse(new ANTLRInputStream(inputStream), listener);
|
||||||
|
|
||||||
|
if ((fragment != null) && (fragment.length() > 0)) {
|
||||||
|
// Search type name in fragment. URI format : see jd.gui.api.feature.UriOpener
|
||||||
|
int index = fragment.indexOf('-');
|
||||||
|
|
||||||
|
if (index != -1) {
|
||||||
|
// Keep type name only
|
||||||
|
fragment = fragment.substring(0, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
return listener.getType(fragment);
|
||||||
|
} else {
|
||||||
|
return listener.getMainType();
|
||||||
|
}
|
||||||
|
} catch (IOException ignore) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static class JavaType implements Type {
|
||||||
|
protected int access;
|
||||||
|
protected String name;
|
||||||
|
protected String superName;
|
||||||
|
protected String outerName;
|
||||||
|
|
||||||
|
protected String displayTypeName;
|
||||||
|
protected String displayInnerTypeName;
|
||||||
|
protected String displayPackageName;
|
||||||
|
|
||||||
|
protected List<Type> innerTypes = new ArrayList<>();
|
||||||
|
protected List<Field> fields = new ArrayList<>();
|
||||||
|
protected List<Method> methods = new ArrayList<>();
|
||||||
|
|
||||||
|
protected JavaType outerType;
|
||||||
|
|
||||||
|
public JavaType(
|
||||||
|
int access, String name, String superName, String outerName,
|
||||||
|
String displayTypeName, String displayInnerTypeName, String displayPackageName,
|
||||||
|
JavaType outerType) {
|
||||||
|
|
||||||
|
this.access = access;
|
||||||
|
this.name = name;
|
||||||
|
this.superName = superName;
|
||||||
|
this.outerName = outerName;
|
||||||
|
this.displayTypeName = displayTypeName;
|
||||||
|
this.displayInnerTypeName = displayInnerTypeName;
|
||||||
|
this.displayPackageName = displayPackageName;
|
||||||
|
this.outerType = outerType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getFlags() { return access; }
|
||||||
|
public String getName() { return name; }
|
||||||
|
public String getSuperName() { return superName; }
|
||||||
|
public String getOuterName() { return outerName; }
|
||||||
|
public String getDisplayTypeName() { return displayTypeName; }
|
||||||
|
public String getDisplayInnerTypeName() { return displayInnerTypeName; }
|
||||||
|
public String getDisplayPackageName() { return displayPackageName; }
|
||||||
|
public Icon getIcon() { return getTypeIcon(access); }
|
||||||
|
public JavaType getOuterType() { return outerType; }
|
||||||
|
public Collection<Type> getInnerTypes() { return innerTypes; }
|
||||||
|
public Collection<Field> getFields() { return fields; }
|
||||||
|
public Collection<Method> getMethods() { return methods; }
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static class JavaField implements Type.Field {
|
||||||
|
protected int access;
|
||||||
|
protected String name;
|
||||||
|
protected String descriptor;
|
||||||
|
|
||||||
|
public JavaField(int access, String name, String descriptor) {
|
||||||
|
this.access = access;
|
||||||
|
this.name = name;
|
||||||
|
this.descriptor = descriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getFlags() { return access; }
|
||||||
|
public String getName() { return name; }
|
||||||
|
public String getDescriptor() { return descriptor; }
|
||||||
|
public Icon getIcon() { return getFieldIcon(access); }
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static class JavaMethod implements Type.Method {
|
||||||
|
protected int access;
|
||||||
|
protected String name;
|
||||||
|
protected String descriptor;
|
||||||
|
|
||||||
|
public JavaMethod(int access, String name, String descriptor) {
|
||||||
|
this.access = access;
|
||||||
|
this.name = name;
|
||||||
|
this.descriptor = descriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getFlags() { return access; }
|
||||||
|
public String getName() { return name; }
|
||||||
|
public String getDescriptor() { return descriptor; }
|
||||||
|
public Icon getIcon() { return getMethodIcon(access); }
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static class Listener extends AbstractJavaListener {
|
||||||
|
|
||||||
|
protected String displayPackageName = "";
|
||||||
|
|
||||||
|
protected JavaType mainType = null;
|
||||||
|
protected JavaType currentType = null;
|
||||||
|
protected ArrayList<Type> rootTypes = new ArrayList<>();
|
||||||
|
protected HashMap<String, Type> types = new HashMap<>();
|
||||||
|
|
||||||
|
public Listener(Container.Entry entry) {
|
||||||
|
super(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type getMainType() {
|
||||||
|
return mainType;
|
||||||
|
}
|
||||||
|
public Type getType(String typeName) {
|
||||||
|
return types.get(typeName);
|
||||||
|
}
|
||||||
|
public ArrayList<Type> getRootTypes() {
|
||||||
|
return rootTypes;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- ANTLR Listener --- //
|
||||||
|
|
||||||
|
public void enterPackageDeclaration(JavaParser.PackageDeclarationContext ctx) {
|
||||||
|
super.enterPackageDeclaration(ctx);
|
||||||
|
displayPackageName = packageName.replace('/', '.');
|
||||||
|
}
|
||||||
|
|
||||||
|
public void enterClassDeclaration(JavaParser.ClassDeclarationContext ctx) { enterTypeDeclaration(ctx, 0); }
|
||||||
|
public void exitClassDeclaration(JavaParser.ClassDeclarationContext ctx) { exitTypeDeclaration(); }
|
||||||
|
|
||||||
|
public void enterEnumDeclaration(JavaParser.EnumDeclarationContext ctx) { enterTypeDeclaration(ctx, JavaType.FLAG_ENUM); }
|
||||||
|
public void exitEnumDeclaration(JavaParser.EnumDeclarationContext ctx) { exitTypeDeclaration(); }
|
||||||
|
|
||||||
|
public void enterInterfaceDeclaration(JavaParser.InterfaceDeclarationContext ctx) { enterTypeDeclaration(ctx, JavaType.FLAG_INTERFACE); }
|
||||||
|
public void exitInterfaceDeclaration(JavaParser.InterfaceDeclarationContext ctx) { exitTypeDeclaration(); }
|
||||||
|
|
||||||
|
public void enterAnnotationTypeDeclaration(JavaParser.AnnotationTypeDeclarationContext ctx) { enterTypeDeclaration(ctx, JavaType.FLAG_ANNOTATION); }
|
||||||
|
public void exitAnnotationTypeDeclaration(JavaParser.AnnotationTypeDeclarationContext ctx) { exitTypeDeclaration(); }
|
||||||
|
|
||||||
|
protected void enterTypeDeclaration(ParserRuleContext ctx, int access) {
|
||||||
|
String name = ctx.getToken(JavaParser.Identifier, 0).getText();
|
||||||
|
|
||||||
|
JavaParser.TypeContext superType = ctx.getRuleContext(JavaParser.TypeContext.class, 0);
|
||||||
|
String superQualifiedTypeName;
|
||||||
|
|
||||||
|
if (superType == null) {
|
||||||
|
superQualifiedTypeName = ((access & JavaType.FLAG_INTERFACE) == 0) ? "java/lang/Object" : "";
|
||||||
|
} else {
|
||||||
|
superQualifiedTypeName = resolveInternalTypeName(superType.classOrInterfaceType().Identifier());
|
||||||
|
}
|
||||||
|
|
||||||
|
access += getTypeDeclarationContextAccessFlag(ctx.getParent());
|
||||||
|
|
||||||
|
if (currentType == null) {
|
||||||
|
String internalTypeName = packageName.isEmpty() ? name : packageName + "/" + name;
|
||||||
|
String outerName = null;
|
||||||
|
String displayTypeName = name;
|
||||||
|
String displayInnerTypeName = null;
|
||||||
|
|
||||||
|
currentType = new JavaType(access, internalTypeName, superQualifiedTypeName, outerName, displayTypeName, displayInnerTypeName, displayPackageName, null);
|
||||||
|
types.put(internalTypeName, currentType);
|
||||||
|
rootTypes.add(currentType);
|
||||||
|
nameToInternalTypeName.put(name, internalTypeName);
|
||||||
|
|
||||||
|
if (mainType == null) {
|
||||||
|
mainType = currentType;
|
||||||
|
} else {
|
||||||
|
// Multi class definitions in the same file
|
||||||
|
String path = entry.getPath();
|
||||||
|
int index = path.lastIndexOf('/') + 1;
|
||||||
|
|
||||||
|
if (path.substring(index).startsWith(name + '.')) {
|
||||||
|
// Select the correct root type
|
||||||
|
mainType = currentType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
String internalTypeName = currentType.getName() + '$' + name;
|
||||||
|
String outerName = currentType.getName();
|
||||||
|
String displayTypeName = currentType.getDisplayTypeName() + '.' + name;
|
||||||
|
String displayInnerTypeName = name;
|
||||||
|
JavaType subType = new JavaType(access, internalTypeName, superQualifiedTypeName, outerName, displayTypeName, displayInnerTypeName, displayPackageName, currentType);
|
||||||
|
|
||||||
|
currentType.getInnerTypes().add(subType);
|
||||||
|
currentType = subType;
|
||||||
|
types.put(internalTypeName, currentType);
|
||||||
|
nameToInternalTypeName.put(name, internalTypeName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void exitTypeDeclaration() {
|
||||||
|
currentType = currentType.getOuterType();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void enterClassBodyDeclaration(JavaParser.ClassBodyDeclarationContext ctx) {
|
||||||
|
if (ctx.getChildCount() == 2) {
|
||||||
|
ParseTree first = ctx.getChild(0);
|
||||||
|
|
||||||
|
if (first instanceof TerminalNode) {
|
||||||
|
if (((TerminalNode)first).getSymbol().getType() == JavaParser.STATIC) {
|
||||||
|
currentType.getMethods().add(new JavaMethod(JavaType.FLAG_STATIC, "<clinit>", "()V"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void enterConstDeclaration(JavaParser.ConstDeclarationContext ctx) {
|
||||||
|
JavaParser.TypeContext typeContext = ctx.type();
|
||||||
|
int access = getClassBodyDeclarationAccessFlag(ctx.getParent().getParent());
|
||||||
|
|
||||||
|
for (JavaParser.ConstantDeclaratorContext constantDeclaratorContext : ctx.constantDeclarator()) {
|
||||||
|
TerminalNode identifier = constantDeclaratorContext.Identifier();
|
||||||
|
String name = identifier.getText();
|
||||||
|
int dimensionOnVariable = countDimension(constantDeclaratorContext.children);
|
||||||
|
String descriptor = createDescriptor(typeContext, dimensionOnVariable);
|
||||||
|
|
||||||
|
currentType.getFields().add(new JavaField(access, name, descriptor));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void enterFieldDeclaration(JavaParser.FieldDeclarationContext ctx) {
|
||||||
|
JavaParser.TypeContext typeContext = ctx.type();
|
||||||
|
int access = getClassBodyDeclarationAccessFlag(ctx.getParent().getParent());
|
||||||
|
|
||||||
|
for (JavaParser.VariableDeclaratorContext declaration : ctx.variableDeclarators().variableDeclarator()) {
|
||||||
|
JavaParser.VariableDeclaratorIdContext variableDeclaratorId = declaration.variableDeclaratorId();
|
||||||
|
TerminalNode identifier = variableDeclaratorId.Identifier();
|
||||||
|
String name = identifier.getText();
|
||||||
|
int dimensionOnVariable = countDimension(variableDeclaratorId.children);
|
||||||
|
String descriptor = createDescriptor(typeContext, dimensionOnVariable);
|
||||||
|
|
||||||
|
currentType.getFields().add(new JavaField(access, name, descriptor));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void enterMethodDeclaration(JavaParser.MethodDeclarationContext ctx) {
|
||||||
|
enterMethodDeclaration(ctx, ctx.Identifier(), ctx.formalParameters(), ctx.type());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void enterInterfaceMethodDeclaration(JavaParser.InterfaceMethodDeclarationContext ctx) {
|
||||||
|
enterMethodDeclaration(ctx, ctx.Identifier(), ctx.formalParameters(), ctx.type());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void enterMethodDeclaration(
|
||||||
|
ParserRuleContext ctx, TerminalNode identifier,
|
||||||
|
JavaParser.FormalParametersContext formalParameters, JavaParser.TypeContext returnType) {
|
||||||
|
|
||||||
|
int access = getClassBodyDeclarationAccessFlag(ctx.getParent().getParent());
|
||||||
|
String name = identifier.getText();
|
||||||
|
String paramDescriptors = createParamDescriptors(formalParameters.formalParameterList());
|
||||||
|
String returnDescriptor = createDescriptor(returnType, 0);
|
||||||
|
String descriptor = paramDescriptors + returnDescriptor;
|
||||||
|
|
||||||
|
currentType.getMethods().add(new JavaMethod(access, name, descriptor));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void enterConstructorDeclaration(JavaParser.ConstructorDeclarationContext ctx) {
|
||||||
|
int access = getClassBodyDeclarationAccessFlag(ctx.getParent().getParent());
|
||||||
|
TerminalNode identifier = ctx.Identifier();
|
||||||
|
String name = identifier.getText();
|
||||||
|
String paramDescriptors = createParamDescriptors(ctx.formalParameters().formalParameterList());
|
||||||
|
String descriptor = paramDescriptors + "V";
|
||||||
|
|
||||||
|
currentType.getMethods().add(new JavaMethod(access, "<init>", descriptor));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String createParamDescriptors(JavaParser.FormalParameterListContext formalParameterList) {
|
||||||
|
StringBuffer paramDescriptors = null;
|
||||||
|
|
||||||
|
if (formalParameterList != null) {
|
||||||
|
List<JavaParser.FormalParameterContext> formalParameters = formalParameterList.formalParameter();
|
||||||
|
paramDescriptors = new StringBuffer("(");
|
||||||
|
|
||||||
|
for (JavaParser.FormalParameterContext formalParameter : formalParameters) {
|
||||||
|
int dimensionOnParameter = countDimension(formalParameter.variableDeclaratorId().children);
|
||||||
|
paramDescriptors.append(createDescriptor(formalParameter.type(), dimensionOnParameter));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (paramDescriptors == null) ? "()" : paramDescriptors.append(')').toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int getTypeDeclarationContextAccessFlag(ParserRuleContext ctx) {
|
||||||
|
int access = 0;
|
||||||
|
|
||||||
|
for (JavaParser.ClassOrInterfaceModifierContext modifierContext : ctx.getRuleContexts(JavaParser.ClassOrInterfaceModifierContext.class)) {
|
||||||
|
access += getAccessFlag(modifierContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
return access;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int getClassBodyDeclarationAccessFlag(ParserRuleContext ctx) {
|
||||||
|
int access = 0;
|
||||||
|
|
||||||
|
for (JavaParser.ModifierContext modifierContext : ctx.getRuleContexts(JavaParser.ModifierContext.class)) {
|
||||||
|
JavaParser.ClassOrInterfaceModifierContext coimc = modifierContext.classOrInterfaceModifier();
|
||||||
|
|
||||||
|
if (coimc != null) {
|
||||||
|
access += getAccessFlag(coimc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return access;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int getAccessFlag(JavaParser.ClassOrInterfaceModifierContext ctx) {
|
||||||
|
if (ctx.getChildCount() == 1) {
|
||||||
|
ParseTree first = ctx.getChild(0);
|
||||||
|
|
||||||
|
if (first instanceof TerminalNode) {
|
||||||
|
switch (((TerminalNode)first).getSymbol().getType()) {
|
||||||
|
case JavaParser.STATIC: return JavaType.FLAG_STATIC;
|
||||||
|
case JavaParser.FINAL: return JavaType.FLAG_FINAL;
|
||||||
|
case JavaParser.ABSTRACT: return JavaType.FLAG_ABSTRACT;
|
||||||
|
case JavaParser.PUBLIC: return JavaType.FLAG_PUBLIC;
|
||||||
|
case JavaParser.PROTECTED: return JavaType.FLAG_PROTECTED;
|
||||||
|
case JavaParser.PRIVATE: return JavaType.FLAG_PRIVATE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2008-2015 Emmanuel Dupuy
|
||||||
|
* This program is made available under the terms of the GPLv3 License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package jd.gui.util.parser.antlr;
|
||||||
|
|
||||||
|
import org.antlr.v4.runtime.CharStream;
|
||||||
|
import org.antlr.v4.runtime.CommonTokenStream;
|
||||||
|
import org.antlr.v4.runtime.tree.ParseTree;
|
||||||
|
import org.antlr.v4.runtime.tree.ParseTreeWalker;
|
||||||
|
|
||||||
|
public class ANTLRParser {
|
||||||
|
|
||||||
|
public static void parse(CharStream input, JavaListener listener) {
|
||||||
|
try {
|
||||||
|
JavaLexer lexer = new JavaLexer(input);
|
||||||
|
CommonTokenStream tokens = new CommonTokenStream(lexer);
|
||||||
|
JavaParser parser = new JavaParser(tokens);
|
||||||
|
|
||||||
|
ParseTree tree = parser.compilationUnit();
|
||||||
|
ParseTreeWalker walker = new ParseTreeWalker();
|
||||||
|
|
||||||
|
walker.walk(listener, tree);
|
||||||
|
} catch (StackOverflowError ignore) {
|
||||||
|
// Too complex source file, probably not written by a human.
|
||||||
|
// This error may happen on Java file generated by ANTLR for example.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,187 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2008-2015 Emmanuel Dupuy
|
||||||
|
* This program is made available under the terms of the GPLv3 License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package jd.gui.util.parser.antlr;
|
||||||
|
|
||||||
|
import jd.gui.api.model.Container;
|
||||||
|
import org.antlr.v4.runtime.tree.ParseTree;
|
||||||
|
import org.antlr.v4.runtime.tree.TerminalNode;
|
||||||
|
import org.antlr.v4.runtime.tree.TerminalNodeImpl;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public abstract class AbstractJavaListener extends JavaBaseListener {
|
||||||
|
|
||||||
|
protected Container.Entry entry;
|
||||||
|
protected String packageName = "";
|
||||||
|
protected HashMap<String, String> nameToInternalTypeName = new HashMap<>();
|
||||||
|
protected StringBuffer sb = new StringBuffer();
|
||||||
|
protected HashMap<String, String> typeNameCache = new HashMap<>();
|
||||||
|
|
||||||
|
public AbstractJavaListener(Container.Entry entry) {
|
||||||
|
this.entry = entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void enterPackageDeclaration(JavaParser.PackageDeclarationContext ctx) {
|
||||||
|
packageName = concatIdentifiers(ctx.qualifiedName().Identifier());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void enterImportDeclaration(JavaParser.ImportDeclarationContext ctx) {
|
||||||
|
List<TerminalNode> identifiers = ctx.qualifiedName().Identifier();
|
||||||
|
int size = identifiers.size();
|
||||||
|
|
||||||
|
if (size > 1) {
|
||||||
|
nameToInternalTypeName.put(identifiers.get(size - 1).getText(), concatIdentifiers(identifiers));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String concatIdentifiers(List<TerminalNode> identifiers) {
|
||||||
|
switch (identifiers.size()) {
|
||||||
|
case 0:
|
||||||
|
return "";
|
||||||
|
case 1:
|
||||||
|
return identifiers.get(0).getText();
|
||||||
|
default:
|
||||||
|
sb.setLength(0);
|
||||||
|
|
||||||
|
for (TerminalNode identifier : identifiers) {
|
||||||
|
sb.append(identifier.getText()).append('/');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove last separator
|
||||||
|
sb.setLength(sb.length() - 1);
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String resolveInternalTypeName(List<TerminalNode> identifiers) {
|
||||||
|
switch (identifiers.size()) {
|
||||||
|
case 0:
|
||||||
|
return null;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
// Search in cache
|
||||||
|
String name = identifiers.get(0).getText();
|
||||||
|
String qualifiedName = typeNameCache.get(name);
|
||||||
|
|
||||||
|
if (qualifiedName != null) {
|
||||||
|
return qualifiedName;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search in imports
|
||||||
|
String imp = nameToInternalTypeName.get(name);
|
||||||
|
|
||||||
|
if (imp != null) {
|
||||||
|
// Import found
|
||||||
|
return imp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search type in same package
|
||||||
|
String prefix = name + '.';
|
||||||
|
|
||||||
|
if (entry.getPath().indexOf('/') != -1) {
|
||||||
|
// Not in root package
|
||||||
|
Container.Entry parent = entry.getParent();
|
||||||
|
int packageLength = parent.getPath().length() + 1;
|
||||||
|
|
||||||
|
for (Container.Entry child : parent.getChildren()) {
|
||||||
|
if (!child.isDirectory() && child.getPath().substring(packageLength).startsWith(prefix)) {
|
||||||
|
qualifiedName = packageName + '/' + name;
|
||||||
|
typeNameCache.put(name, qualifiedName);
|
||||||
|
return qualifiedName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search type in root package
|
||||||
|
for (Container.Entry child : entry.getContainer().getRoot().getChildren()) {
|
||||||
|
if (!child.isDirectory() && child.getPath().startsWith(prefix)) {
|
||||||
|
typeNameCache.put(name, name);
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search type in 'java.lang'
|
||||||
|
try {
|
||||||
|
if (Class.forName("java.lang." + name) != null) {
|
||||||
|
qualifiedName = "java/lang/" + name;
|
||||||
|
typeNameCache.put(name, qualifiedName);
|
||||||
|
return qualifiedName;
|
||||||
|
}
|
||||||
|
} catch (ClassNotFoundException ignore) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type not found
|
||||||
|
qualifiedName = "*/" + name;
|
||||||
|
typeNameCache.put(name, qualifiedName);
|
||||||
|
return qualifiedName;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Qualified type name -> Nothing to do
|
||||||
|
return concatIdentifiers(identifiers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String createDescriptor(JavaParser.TypeContext typeContext, int dimension) {
|
||||||
|
if (typeContext == null) {
|
||||||
|
return "V";
|
||||||
|
} else {
|
||||||
|
dimension += countDimension(typeContext.children);
|
||||||
|
JavaParser.PrimitiveTypeContext primitive = typeContext.primitiveType();
|
||||||
|
String name;
|
||||||
|
|
||||||
|
if (primitive == null) {
|
||||||
|
JavaParser.ClassOrInterfaceTypeContext type = typeContext.classOrInterfaceType();
|
||||||
|
List<JavaParser.TypeArgumentsContext> typeArgumentsContexts = type.typeArguments();
|
||||||
|
|
||||||
|
if (typeArgumentsContexts.size() == 1) {
|
||||||
|
JavaParser.TypeArgumentsContext typeArgumentsContext = typeArgumentsContexts.get(0);
|
||||||
|
List<JavaParser.TypeArgumentContext> typeArguments = typeArgumentsContext.typeArgument();
|
||||||
|
} else if (typeArgumentsContexts.size() > 1) {
|
||||||
|
throw new RuntimeException("UNEXPECTED");
|
||||||
|
}
|
||||||
|
|
||||||
|
name = "L" + resolveInternalTypeName(type.Identifier()) + ";";
|
||||||
|
} else {
|
||||||
|
// Search primitive
|
||||||
|
switch (primitive.getText()) {
|
||||||
|
case "boolean": name = "Z"; break;
|
||||||
|
case "byte": name = "B"; break;
|
||||||
|
case "char": name = "C"; break;
|
||||||
|
case "double": name = "D"; break;
|
||||||
|
case "float": name = "F"; break;
|
||||||
|
case "int": name = "I"; break;
|
||||||
|
case "long": name = "J"; break;
|
||||||
|
case "short": name = "S"; break;
|
||||||
|
case "void": name = "V"; break;
|
||||||
|
default:
|
||||||
|
throw new RuntimeException("UNEXPECTED PRIMITIVE");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (dimension) {
|
||||||
|
case 0: return name;
|
||||||
|
case 1: return "[" + name;
|
||||||
|
case 2: return "[[" + name;
|
||||||
|
default: return new String(new char[dimension]).replace('\0', '[') + name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int countDimension(List<ParseTree> children) {
|
||||||
|
int dimension = 0;
|
||||||
|
|
||||||
|
for (ParseTree child : children) {
|
||||||
|
if (child instanceof TerminalNodeImpl) {
|
||||||
|
if (((TerminalNodeImpl)child).getSymbol().getType() == JavaParser.LBRACK)
|
||||||
|
dimension++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dimension;
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
jd.gui.service.fileloader.ClassFileLoaderProvider
|
jd.gui.service.fileloader.ClassFileLoaderProvider
|
||||||
jd.gui.service.fileloader.EarFileLoaderProvider
|
jd.gui.service.fileloader.EarFileLoaderProvider
|
||||||
jd.gui.service.fileloader.JarFileLoaderProvider
|
jd.gui.service.fileloader.JarFileLoaderProvider
|
||||||
|
jd.gui.service.fileloader.JavaFileLoaderProvider
|
||||||
jd.gui.service.fileloader.LogFileLoaderProvider
|
jd.gui.service.fileloader.LogFileLoaderProvider
|
||||||
jd.gui.service.fileloader.WarFileLoaderProvider
|
jd.gui.service.fileloader.WarFileLoaderProvider
|
||||||
jd.gui.service.fileloader.ZipFileLoaderProvider
|
jd.gui.service.fileloader.ZipFileLoaderProvider
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
jd.gui.service.indexer.DirectoryIndexerProvider
|
jd.gui.service.indexer.DirectoryIndexerProvider
|
||||||
jd.gui.service.indexer.ClassFileIndexerProvider
|
jd.gui.service.indexer.ClassFileIndexerProvider
|
||||||
jd.gui.service.indexer.EjbJarXmlFileIndexerProvider
|
jd.gui.service.indexer.EjbJarXmlFileIndexerProvider
|
||||||
|
jd.gui.service.indexer.JavaFileIndexerProvider
|
||||||
jd.gui.service.indexer.MetainfServiceFileIndexerProvider
|
jd.gui.service.indexer.MetainfServiceFileIndexerProvider
|
||||||
jd.gui.service.indexer.TextFileIndexerProvider
|
jd.gui.service.indexer.TextFileIndexerProvider
|
||||||
jd.gui.service.indexer.WebXmlFileIndexerProvider
|
jd.gui.service.indexer.WebXmlFileIndexerProvider
|
||||||
|
@ -7,7 +7,7 @@ jd.gui.service.treenode.EjbJarXmlFileTreeNodeFactoryProvider
|
|||||||
jd.gui.service.treenode.FileTreeNodeFactoryProvider
|
jd.gui.service.treenode.FileTreeNodeFactoryProvider
|
||||||
jd.gui.service.treenode.HtmlFileTreeNodeFactoryProvider
|
jd.gui.service.treenode.HtmlFileTreeNodeFactoryProvider
|
||||||
jd.gui.service.treenode.JarFileTreeNodeFactoryProvider
|
jd.gui.service.treenode.JarFileTreeNodeFactoryProvider
|
||||||
#jd.gui.service.treenode.JavaFileTreeNodeFactoryProvider
|
jd.gui.service.treenode.JavaFileTreeNodeFactoryProvider
|
||||||
jd.gui.service.treenode.JavascriptFileTreeNodeFactoryProvider
|
jd.gui.service.treenode.JavascriptFileTreeNodeFactoryProvider
|
||||||
jd.gui.service.treenode.JspFileTreeNodeFactoryProvider
|
jd.gui.service.treenode.JspFileTreeNodeFactoryProvider
|
||||||
jd.gui.service.treenode.ManifestFileTreeNodeFactoryProvider
|
jd.gui.service.treenode.ManifestFileTreeNodeFactoryProvider
|
||||||
|
@ -1 +1,2 @@
|
|||||||
jd.gui.service.type.ClassFileTypeFactoryProvider
|
jd.gui.service.type.ClassFileTypeFactoryProvider
|
||||||
|
jd.gui.service.type.JavaFileTypeFactoryProvider
|
||||||
|
BIN
services/src/main/resources/images/jcu_obj.png
Normal file
BIN
services/src/main/resources/images/jcu_obj.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 738 B |
@ -7,9 +7,9 @@ package jd.gui.view.component
|
|||||||
|
|
||||||
class ClassFilePageTest extends GroovyTestCase {
|
class ClassFilePageTest extends GroovyTestCase {
|
||||||
|
|
||||||
HashMap<String, ClassFilePage.DeclarationData> initDeclarations() {
|
HashMap<String, TypePage.DeclarationData> initDeclarations() {
|
||||||
def data = new ClassFilePage.DeclarationData(0, 1, "Test", "test", "I")
|
def data = new TypePage.DeclarationData(0, 1, "Test", "test", "I")
|
||||||
HashMap<String, ClassFilePage.DeclarationData> declarations = [:]
|
HashMap<String, TypePage.DeclarationData> declarations = [:]
|
||||||
|
|
||||||
// Init type declarations
|
// Init type declarations
|
||||||
declarations.put("Test", data)
|
declarations.put("Test", data)
|
||||||
@ -43,16 +43,16 @@ class ClassFilePageTest extends GroovyTestCase {
|
|||||||
TreeMap<Integer, HyperlinkPage.HyperlinkData> initHyperlinks() {
|
TreeMap<Integer, HyperlinkPage.HyperlinkData> initHyperlinks() {
|
||||||
def hyperlinks = new TreeMap<Integer, HyperlinkPage.HyperlinkData>()
|
def hyperlinks = new TreeMap<Integer, HyperlinkPage.HyperlinkData>()
|
||||||
|
|
||||||
hyperlinks.put(0, new ClassFilePage.HyperlinkReferenceData(0, 1, new ClassFilePage.ReferenceData("java/lang/Integer", "MAX_VALUE", "I", "Test")))
|
hyperlinks.put(0, new TypePage.HyperlinkReferenceData(0, 1, new TypePage.ReferenceData("java/lang/Integer", "MAX_VALUE", "I", "Test")))
|
||||||
hyperlinks.put(0, new ClassFilePage.HyperlinkReferenceData(0, 1, new ClassFilePage.ReferenceData("java/lang/Integer", "toString", "()Ljava/lang/String;", "Test")))
|
hyperlinks.put(0, new TypePage.HyperlinkReferenceData(0, 1, new TypePage.ReferenceData("java/lang/Integer", "toString", "()Ljava/lang/String;", "Test")))
|
||||||
|
|
||||||
return hyperlinks
|
return hyperlinks
|
||||||
}
|
}
|
||||||
|
|
||||||
ArrayList<ClassFilePage.StringData> initStrings() {
|
ArrayList<TypePage.StringData> initStrings() {
|
||||||
def strings = new ArrayList<ClassFilePage.StringData>()
|
def strings = new ArrayList<TypePage.StringData>()
|
||||||
|
|
||||||
strings.add(new ClassFilePage.StringData(0, 3, "abc", "Test"))
|
strings.add(new TypePage.StringData(0, 3, "abc", "Test"))
|
||||||
|
|
||||||
return strings
|
return strings
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2008-2015 Emmanuel Dupuy
|
||||||
|
* This program is made available under the terms of the GPLv3 License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package jd.gui.view.component
|
||||||
|
|
||||||
|
class JavaFilePageTest extends GroovyTestCase {
|
||||||
|
|
||||||
|
HashMap<String, TypePage.DeclarationData> initDeclarations() {
|
||||||
|
def data = new TypePage.DeclarationData(0, 1, "Test", "test", "I")
|
||||||
|
HashMap<String, TypePage.DeclarationData> declarations = [:]
|
||||||
|
|
||||||
|
// Init type declarations
|
||||||
|
declarations.put("Test", data)
|
||||||
|
declarations.put("test/Test", data)
|
||||||
|
declarations.put("*/Test", data)
|
||||||
|
|
||||||
|
// Init field declarations
|
||||||
|
declarations.put("Test-attributeInt-I", data)
|
||||||
|
declarations.put("Test-attributeBoolean-Z", data)
|
||||||
|
declarations.put("Test-attributeArrayBoolean-[[Z", data)
|
||||||
|
declarations.put("Test-attributeString-Ljava/lang/String;", data)
|
||||||
|
|
||||||
|
declarations.put("test/Test-attributeInt-I", data)
|
||||||
|
declarations.put("test/Test-attributeBoolean-Z", data)
|
||||||
|
declarations.put("test/Test-attributeArrayBoolean-[[Z", data)
|
||||||
|
declarations.put("test/Test-attributeString-Ljava/lang/String;", data)
|
||||||
|
|
||||||
|
declarations.put("*/Test-attributeBoolean-?", data)
|
||||||
|
declarations.put("*/Test-attributeBoolean-Z", data)
|
||||||
|
declarations.put("test/Test-attributeBoolean-?", data)
|
||||||
|
|
||||||
|
// Init method declarations
|
||||||
|
declarations.put("*/Test-getInt-()I", data)
|
||||||
|
declarations.put("*/Test-getString-()Ljava/lang/String;", data)
|
||||||
|
declarations.put("*/Test-add-(JJ)J", data)
|
||||||
|
declarations.put("*/Test-createBuffer-(I)[C", data)
|
||||||
|
|
||||||
|
declarations.put("test/Test-getInt-(*)?", data)
|
||||||
|
declarations.put("test/Test-getString-(*)?", data)
|
||||||
|
declarations.put("test/Test-add-(*)?", data)
|
||||||
|
declarations.put("test/Test-createBuffer-(*)?", data)
|
||||||
|
|
||||||
|
declarations.put("*/Test-getInt-(*)?", data)
|
||||||
|
declarations.put("*/Test-getString-(*)?", data)
|
||||||
|
declarations.put("*/Test-add-(*)?", data)
|
||||||
|
declarations.put("*/Test-createBuffer-(*)?", data)
|
||||||
|
|
||||||
|
return declarations
|
||||||
|
}
|
||||||
|
|
||||||
|
void testMatchFragmentAndAddDocumentRange() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void testMatchQueryAndAddDocumentRange() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void testMatchScope() {
|
||||||
|
}
|
||||||
|
}
|
@ -29,6 +29,16 @@
|
|||||||
<key>LSIsAppleDefaultForType</key> <true/>
|
<key>LSIsAppleDefaultForType</key> <true/>
|
||||||
<key>LSTypeIsPackage</key> <false/>
|
<key>LSTypeIsPackage</key> <false/>
|
||||||
</dict>
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleTypeExtensions</key>
|
||||||
|
<array>
|
||||||
|
<string>java</string>
|
||||||
|
</array>
|
||||||
|
<key>CFBundleTypeRole</key> <string>Viewer</string>
|
||||||
|
<key>CFBundleTypeName</key> <string>Java File</string>
|
||||||
|
<key>LSIsAppleDefaultForType</key> <false/>
|
||||||
|
<key>LSTypeIsPackage</key> <false/>
|
||||||
|
</dict>
|
||||||
<dict>
|
<dict>
|
||||||
<key>CFBundleTypeExtensions</key>
|
<key>CFBundleTypeExtensions</key>
|
||||||
<array>
|
<array>
|
||||||
|
Loading…
Reference in New Issue
Block a user