mirror of
https://github.com/java-decompiler/jd-gui.git
synced 2024-12-03 10:10:55 +00:00
Adds support for JAVA files
This commit is contained in:
parent
411348dc6b
commit
e8a49c4e75
@ -10,3 +10,59 @@ dependencies {
|
||||
compile project(':api')
|
||||
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 jd.gui.api.API
|
||||
import jd.gui.api.feature.UriOpenable
|
||||
|
||||
import java.nio.file.Paths
|
||||
|
||||
class ClassFileLoaderProvider extends AbstractFileLoaderProvider {
|
||||
class ClassFileLoaderProvider extends AbstractTypeFileLoaderProvider {
|
||||
|
||||
String[] getExtensions() { ['class'] }
|
||||
String getDescription() { 'Class files (*.class)' }
|
||||
@ -22,48 +19,10 @@ class ClassFileLoaderProvider extends AbstractFileLoaderProvider {
|
||||
|
||||
boolean load(API api, File file) {
|
||||
file.withInputStream { is ->
|
||||
ClassReader classReader = new ClassReader(is)
|
||||
def classReader = new ClassReader(is)
|
||||
def pathInFile = classReader.className.replace('/', File.separator) + '.class'
|
||||
|
||||
// Search root path
|
||||
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
|
||||
}
|
||||
}
|
||||
return load(api, file, pathInFile)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
import groovy.transform.CompileStatic
|
||||
import jd.gui.api.API
|
||||
import jd.gui.api.feature.PageCreator
|
||||
import jd.gui.api.feature.TreeNodeExpandable
|
||||
@ -21,13 +20,13 @@ abstract class AbstractTypeFileTreeNodeFactoryProvider extends AbstractTreeNodeF
|
||||
|
||||
static class BaseTreeNode extends DefaultMutableTreeNode implements UriGettable, PageCreator {
|
||||
Container.Entry entry
|
||||
PageFactory pageFactory;
|
||||
PageAndTipFactory factory;
|
||||
URI uri
|
||||
|
||||
BaseTreeNode(Container.Entry entry, String fragment, Object userObject, PageFactory pageFactory) {
|
||||
BaseTreeNode(Container.Entry entry, String fragment, Object userObject, PageAndTipFactory factory) {
|
||||
super(userObject)
|
||||
this.entry = entry
|
||||
this.pageFactory = pageFactory
|
||||
this.factory = factory
|
||||
|
||||
if (fragment) {
|
||||
def uri = entry.uri
|
||||
@ -43,50 +42,20 @@ abstract class AbstractTypeFileTreeNodeFactoryProvider extends AbstractTreeNodeF
|
||||
// --- PageCreator --- //
|
||||
public <T extends JComponent & UriGettable> T createPage(API api) {
|
||||
// Lazy 'tip' initialization
|
||||
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>"
|
||||
|
||||
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)
|
||||
userObject.tip = factory.makeTip(api, entry)
|
||||
return factory.makePage(api, entry)
|
||||
}
|
||||
}
|
||||
|
||||
static class FileTreeNode extends BaseTreeNode implements TreeNodeExpandable {
|
||||
boolean initialized
|
||||
|
||||
FileTreeNode(Container.Entry entry, Object userObject, PageFactory pageFactory) {
|
||||
this(entry, null, userObject, pageFactory)
|
||||
FileTreeNode(Container.Entry entry, Object userObject, PageAndTipFactory pageAndTipFactory) {
|
||||
this(entry, null, userObject, pageAndTipFactory)
|
||||
}
|
||||
|
||||
FileTreeNode(Container.Entry entry, String fragment, Object userObject, PageFactory pageFactory) {
|
||||
super(entry, fragment, userObject, pageFactory)
|
||||
FileTreeNode(Container.Entry entry, String fragment, Object userObject, PageAndTipFactory factory) {
|
||||
super(entry, fragment, userObject, factory)
|
||||
initialized = false
|
||||
// Add dummy node
|
||||
add(new DefaultMutableTreeNode())
|
||||
@ -97,9 +66,10 @@ abstract class AbstractTypeFileTreeNodeFactoryProvider extends AbstractTreeNodeF
|
||||
if (!initialized) {
|
||||
removeAllChildren()
|
||||
// Create type node
|
||||
def type = api.getTypeFactory(entry)?.make(api, entry, null)
|
||||
if (type) {
|
||||
add(new TypeTreeNode(entry, type, new TreeNodeBean(label: type.displayTypeName, icon: type.icon), pageFactory))
|
||||
def types = api.getTypeFactory(entry)?.make(api, entry)
|
||||
|
||||
for (def type : types) {
|
||||
add(new TypeTreeNode(entry, type, new TreeNodeBean(label: type.displayTypeName, icon: type.icon), factory))
|
||||
}
|
||||
|
||||
initialized = true
|
||||
@ -111,8 +81,8 @@ abstract class AbstractTypeFileTreeNodeFactoryProvider extends AbstractTreeNodeF
|
||||
boolean initialized
|
||||
Type type
|
||||
|
||||
TypeTreeNode(Container.Entry entry, Type type, Object userObject, PageFactory pageFactory) {
|
||||
super(entry, type.name, userObject, pageFactory)
|
||||
TypeTreeNode(Container.Entry entry, Type type, Object userObject, PageAndTipFactory factory) {
|
||||
super(entry, type.name, userObject, factory)
|
||||
this.initialized = false
|
||||
this.type = type
|
||||
// Add dummy node
|
||||
@ -134,7 +104,7 @@ abstract class AbstractTypeFileTreeNodeFactoryProvider extends AbstractTreeNodeF
|
||||
type.innerTypes.sort { t1, t2 ->
|
||||
t1.name.compareTo(t2.name)
|
||||
}.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
|
||||
@ -148,7 +118,7 @@ abstract class AbstractTypeFileTreeNodeFactoryProvider extends AbstractTreeNodeF
|
||||
}.sort { f1, f2 ->
|
||||
f1.label.compareTo(f2.label)
|
||||
}.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
|
||||
@ -161,7 +131,7 @@ abstract class AbstractTypeFileTreeNodeFactoryProvider extends AbstractTreeNodeF
|
||||
}.sort { m1, m2 ->
|
||||
m1.label.compareTo(m2.label)
|
||||
}.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
|
||||
@ -400,8 +370,8 @@ abstract class AbstractTypeFileTreeNodeFactoryProvider extends AbstractTreeNodeF
|
||||
}
|
||||
|
||||
static class FieldOrMethodTreeNode extends BaseTreeNode {
|
||||
FieldOrMethodTreeNode(Container.Entry entry, String fragment, Object userObject, PageFactory pageFactory) {
|
||||
super(entry, fragment, userObject, pageFactory)
|
||||
FieldOrMethodTreeNode(Container.Entry entry, String fragment, Object userObject, PageAndTipFactory factory) {
|
||||
super(entry, fragment, userObject, factory)
|
||||
}
|
||||
}
|
||||
|
||||
@ -409,8 +379,9 @@ abstract class AbstractTypeFileTreeNodeFactoryProvider extends AbstractTreeNodeF
|
||||
String fragment, label
|
||||
Icon icon
|
||||
}
|
||||
|
||||
interface PageFactory {
|
||||
public <T extends JComponent & UriGettable> T make(API api, Container.Entry entry);
|
||||
|
||||
interface PageAndTipFactory {
|
||||
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
|
||||
|
||||
import groovy.transform.CompileStatic
|
||||
import jd.gui.api.API
|
||||
import jd.gui.api.feature.UriGettable
|
||||
import jd.gui.api.model.Container
|
||||
@ -17,6 +18,8 @@ import javax.swing.tree.DefaultMutableTreeNode
|
||||
class ClassFileTreeNodeFactoryProvider extends AbstractTypeFileTreeNodeFactoryProvider {
|
||||
static final ImageIcon CLASS_FILE_ICON = new ImageIcon(ClassFileTreeNodeFactoryProvider.class.classLoader.getResource('images/classf_obj.png'))
|
||||
|
||||
static final Factory FACTORY = new Factory();
|
||||
|
||||
static {
|
||||
// Early class loading
|
||||
try {
|
||||
@ -36,9 +39,46 @@ class ClassFileTreeNodeFactoryProvider extends AbstractTypeFileTreeNodeFactoryPr
|
||||
return new FileTreeNode(
|
||||
entry,
|
||||
new TreeNodeBean(label:name, icon:CLASS_FILE_ICON),
|
||||
new AbstractTypeFileTreeNodeFactoryProvider.PageFactory() {
|
||||
public <T extends JComponent & UriGettable> T make(API a, Container.Entry e) { new ClassFilePage(a, e) }
|
||||
}
|
||||
FACTORY
|
||||
)
|
||||
}
|
||||
|
||||
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.feature.*
|
||||
import jd.gui.api.model.Container
|
||||
import jd.gui.api.model.Indexes
|
||||
import jd.gui.util.decompiler.ClassFileSourcePrinter
|
||||
import jd.gui.util.decompiler.ContainerLoader
|
||||
import jd.gui.util.decompiler.GuiPreferences
|
||||
import jd.gui.util.matcher.DescriptorMatcher
|
||||
import org.fife.ui.rsyntaxtextarea.DocumentRange
|
||||
import org.fife.ui.rsyntaxtextarea.SyntaxConstants
|
||||
|
||||
import javax.swing.text.DefaultCaret
|
||||
import java.awt.Color
|
||||
import java.awt.Point
|
||||
import java.util.regex.Pattern
|
||||
|
||||
class ClassFilePage
|
||||
extends CustomLineNumbersPage
|
||||
implements UriGettable, IndexesChangeListener, LineNumberNavigable, FocusedTypeGettable, PreferencesChangeListener {
|
||||
class ClassFilePage extends TypePage implements PreferencesChangeListener {
|
||||
|
||||
protected static final String ESCAPE_UNICODE_CHARACTERS = 'ClassFileViewerPreferences.escapeUnicodeCharacters'
|
||||
protected static final String OMIT_THIS_PREFIX = 'ClassFileViewerPreferences.omitThisPrefix'
|
||||
@ -37,15 +31,6 @@ class ClassFilePage
|
||||
|
||||
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
|
||||
|
||||
static {
|
||||
@ -69,9 +54,7 @@ class ClassFilePage
|
||||
}
|
||||
|
||||
ClassFilePage(API api, Container.Entry entry) {
|
||||
// Init attributes
|
||||
this.api = api
|
||||
this.entry = entry
|
||||
super(api, entry)
|
||||
// Init view
|
||||
errorForeground = Color.decode(api.preferences.get('JdGuiPreferences.errorBackgroundColor'))
|
||||
// Display source
|
||||
@ -111,43 +94,18 @@ class ClassFilePage
|
||||
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 }
|
||||
|
||||
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
|
||||
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)
|
||||
}
|
||||
if (v == null) {
|
||||
return defaultValue;
|
||||
} else {
|
||||
return Boolean.valueOf(v);
|
||||
}
|
||||
}
|
||||
|
||||
// --- UriGettable --- //
|
||||
URI getUri() { entry.uri }
|
||||
String getSyntaxStyle() { SyntaxConstants.SYNTAX_STYLE_JAVA }
|
||||
|
||||
// --- ContentSavable --- //
|
||||
String getFileName() {
|
||||
@ -156,89 +114,6 @@ class ClassFilePage
|
||||
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 --- //
|
||||
int getMaximumLineNumber() { maximumLineNumber }
|
||||
|
||||
@ -253,218 +128,6 @@ class ClassFilePage
|
||||
|
||||
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 --- //
|
||||
void preferencesChanged(Map<String, String> preferences) {
|
||||
def caret = textArea.caret
|
||||
@ -477,18 +140,16 @@ class ClassFilePage
|
||||
|
||||
@CompileStatic
|
||||
class Printer extends ClassFileSourcePrinter {
|
||||
protected StringBuffer stringBuffer
|
||||
protected StringBuffer stringBuffer = new StringBuffer(10*1024)
|
||||
protected boolean realignmentLineNumber
|
||||
protected boolean showPrefixThis
|
||||
protected boolean unicodeEscape
|
||||
protected HashMap<String, ReferenceData> referencesCache
|
||||
protected HashMap<String, TypePage.ReferenceData> referencesCache = new HashMap<>()
|
||||
|
||||
Printer(GuiPreferences preferences) {
|
||||
this.stringBuffer = new StringBuffer(10*1024)
|
||||
this.realignmentLineNumber = preferences.getRealignmentLineNumber()
|
||||
this.showPrefixThis = preferences.isShowPrefixThis()
|
||||
this.unicodeEscape = preferences.isUnicodeEscape()
|
||||
this.referencesCache = new HashMap<>()
|
||||
}
|
||||
|
||||
boolean getRealignmentLineNumber() { realignmentLineNumber }
|
||||
@ -496,8 +157,7 @@ class ClassFilePage
|
||||
boolean isUnicodeEscape() { unicodeEscape }
|
||||
|
||||
void append(char c) { stringBuffer.append(c) }
|
||||
void append(String s) {
|
||||
stringBuffer.append(s) }
|
||||
void append(String s) { stringBuffer.append(s) }
|
||||
|
||||
// Manage line number and misalignment
|
||||
int textAreaLineNumber = 1
|
||||
@ -526,52 +186,52 @@ class ClassFilePage
|
||||
}
|
||||
}
|
||||
|
||||
// --- Manage strings --- //
|
||||
// --- Add strings --- //
|
||||
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)
|
||||
}
|
||||
|
||||
// --- Manage references --- //
|
||||
// --- Add references --- //
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
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)
|
||||
}
|
||||
|
||||
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 reference = referencesCache.get(key)
|
||||
|
||||
if (reference == null) {
|
||||
reference = new ReferenceData(internalName, name, descriptor, scopeInternalName)
|
||||
reference = new TypePage.ReferenceData(internalName, name, descriptor, scopeInternalName)
|
||||
referencesCache.put(key, reference)
|
||||
references.add(reference)
|
||||
}
|
||||
@ -579,132 +239,37 @@ class ClassFilePage
|
||||
return reference
|
||||
}
|
||||
|
||||
// --- Manage declarations --- //
|
||||
// --- Add declarations --- //
|
||||
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)
|
||||
typeDeclarations.put(stringBuffer.length(), data)
|
||||
super.printTypeDeclaration(internalName, name)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
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)
|
||||
}
|
||||
|
||||
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.*
|
||||
|
||||
class EjbJarXmlFilePage extends TypeHyperlinkPage implements UriGettable, IndexesChangeListener {
|
||||
class EjbJarXmlFilePage extends TypeReferencePage implements UriGettable, IndexesChangeListener {
|
||||
protected API api
|
||||
protected Container.Entry entry
|
||||
protected Collection<Indexes> collectionOfIndexes
|
||||
@ -133,7 +133,7 @@ class EjbJarXmlFilePage extends TypeHyperlinkPage implements UriGettable, Indexe
|
||||
int startIndex = position + text.indexOf(trim)
|
||||
int endIndex = startIndex + trim.length()
|
||||
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 --- //
|
||||
int getMaximumLineNumber() {
|
||||
return textArea.getLineOfOffset(textArea.document.length)
|
||||
return textArea.getLineOfOffset(textArea.document.length) + 1
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
abstract class TypeHyperlinkPage extends HyperlinkPage {
|
||||
/**
|
||||
* Page containing type references (Hyperlinks to pages of type)
|
||||
*/
|
||||
abstract class TypeReferencePage extends HyperlinkPage {
|
||||
|
||||
// --- UriOpenable --- //
|
||||
boolean openUri(URI uri) {
|
@ -16,7 +16,7 @@ import org.fife.ui.rsyntaxtextarea.SyntaxConstants
|
||||
import java.awt.Point
|
||||
|
||||
|
||||
class WebXmlFilePage extends TypeHyperlinkPage implements UriGettable, IndexesChangeListener {
|
||||
class WebXmlFilePage extends TypeReferencePage implements UriGettable, IndexesChangeListener {
|
||||
protected API api
|
||||
protected Container.Entry entry
|
||||
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))
|
||||
|
||||
// Open link
|
||||
if (hyperlinkData instanceof TypeHyperlinkPage.TypeHyperlinkData) {
|
||||
if (hyperlinkData instanceof TypeReferencePage.TypeHyperlinkData) {
|
||||
def internalTypeName = hyperlinkData.internalTypeName
|
||||
def entries = collectionOfIndexes?.collect { it.getIndex('typeDeclarations')?.get(internalTypeName) }.flatten().grep { it!=null }
|
||||
def rootUri = entry.container.root.uri.toString()
|
||||
@ -163,7 +163,7 @@ class WebXmlFilePage extends TypeHyperlinkPage implements UriGettable, IndexesCh
|
||||
addHyperlink(new PathHyperlinkData(startIndex, endIndex, trim))
|
||||
} else {
|
||||
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;
|
||||
|
||||
import jd.gui.api.model.Container;
|
||||
import jd.gui.api.model.Indexes;
|
||||
import jd.gui.spi.Indexer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.*;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
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()]);
|
||||
}
|
||||
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.Indexes;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.*;
|
||||
|
||||
@ -20,17 +19,17 @@ import java.util.*;
|
||||
* Unsafe thread implementation of class file indexer.
|
||||
*/
|
||||
public class ClassFileIndexerProvider extends AbstractIndexerProvider {
|
||||
protected Set<String> typeDeclarationSet = new HashSet<>();
|
||||
protected Set<String> constructorDeclarationSet = new HashSet<>();
|
||||
protected Set<String> methodDeclarationSet = new HashSet<>();
|
||||
protected Set<String> fieldDeclarationSet = new HashSet<>();
|
||||
protected Set<String> typeReferenceSet = new HashSet<>();
|
||||
protected Set<String> constructorReferenceSet = new HashSet<>();
|
||||
protected Set<String> methodReferenceSet = new HashSet<>();
|
||||
protected Set<String> fieldReferenceSet = new HashSet<>();
|
||||
protected Set<String> stringSet = new HashSet<>();
|
||||
protected Set<String> superTypeNameSet = new HashSet<>();
|
||||
protected Set<String> descriptorSet = new HashSet<>();
|
||||
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 HashSet<String> superTypeNameSet = new HashSet<>();
|
||||
protected HashSet<String> descriptorSet = new HashSet<>();
|
||||
|
||||
protected ClassIndexer classIndexer = new ClassIndexer(
|
||||
typeDeclarationSet, constructorDeclarationSet, methodDeclarationSet,
|
||||
@ -72,11 +71,9 @@ public class ClassFileIndexerProvider extends AbstractIndexerProvider {
|
||||
superTypeNameSet.clear();
|
||||
descriptorSet.clear();
|
||||
|
||||
InputStream inputStream = null;
|
||||
|
||||
try {
|
||||
try (InputStream inputStream = entry.getInputStream()) {
|
||||
// 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);
|
||||
|
||||
// Index descriptors
|
||||
@ -159,32 +156,17 @@ public class ClassFileIndexerProvider extends AbstractIndexerProvider {
|
||||
}
|
||||
|
||||
} 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 Set<String> typeDeclarationSet;
|
||||
protected Set<String> constructorDeclarationSet;
|
||||
protected Set<String> methodDeclarationSet;
|
||||
protected Set<String> fieldDeclarationSet;
|
||||
protected Set<String> typeReferenceSet;
|
||||
protected Set<String> superTypeNameSet;
|
||||
protected Set<String> descriptorSet;
|
||||
protected HashSet<String> typeDeclarationSet;
|
||||
protected HashSet<String> constructorDeclarationSet;
|
||||
protected HashSet<String> methodDeclarationSet;
|
||||
protected HashSet<String> fieldDeclarationSet;
|
||||
protected HashSet<String> typeReferenceSet;
|
||||
protected HashSet<String> superTypeNameSet;
|
||||
protected HashSet<String> descriptorSet;
|
||||
|
||||
protected AnnotationIndexer annotationIndexer;
|
||||
protected FieldIndexer fieldIndexer;
|
||||
@ -193,9 +175,9 @@ public class ClassFileIndexerProvider extends AbstractIndexerProvider {
|
||||
protected String name;
|
||||
|
||||
public ClassIndexer(
|
||||
Set<String> typeDeclarationSet, Set<String> constructorDeclarationSet,
|
||||
Set<String> methodDeclarationSet, Set<String> fieldDeclarationSet,
|
||||
Set<String> typeReferenceSet, Set<String> superTypeNameSet, Set<String> descriptorSet) {
|
||||
HashSet<String> typeDeclarationSet, HashSet<String> constructorDeclarationSet,
|
||||
HashSet<String> methodDeclarationSet, HashSet<String> fieldDeclarationSet,
|
||||
HashSet<String> typeReferenceSet, HashSet<String> superTypeNameSet, HashSet<String> descriptorSet) {
|
||||
super(Opcodes.ASM5);
|
||||
|
||||
this.typeDeclarationSet = typeDeclarationSet;
|
||||
@ -258,9 +240,9 @@ public class ClassFileIndexerProvider extends AbstractIndexerProvider {
|
||||
}
|
||||
|
||||
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);
|
||||
this.typeReferenceSet = typeReferenceSet;
|
||||
}
|
||||
@ -271,9 +253,9 @@ public class ClassFileIndexerProvider extends AbstractIndexerProvider {
|
||||
}
|
||||
|
||||
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);
|
||||
this.descriptorSet = descriptorSet;
|
||||
}
|
||||
@ -289,10 +271,10 @@ public class ClassFileIndexerProvider extends AbstractIndexerProvider {
|
||||
}
|
||||
|
||||
protected static class FieldIndexer extends FieldVisitor {
|
||||
protected Set<String> descriptorSet;
|
||||
protected HashSet<String> descriptorSet;
|
||||
protected AnnotationIndexer annotationIndexer;
|
||||
|
||||
public FieldIndexer(Set<String> descriptorSet, AnnotationIndexer annotationInexer) {
|
||||
public FieldIndexer(HashSet<String> descriptorSet, AnnotationIndexer annotationInexer) {
|
||||
super(Opcodes.ASM5);
|
||||
this.descriptorSet = descriptorSet;
|
||||
this.annotationIndexer = annotationInexer;
|
||||
@ -310,10 +292,10 @@ public class ClassFileIndexerProvider extends AbstractIndexerProvider {
|
||||
}
|
||||
|
||||
protected static class MethodIndexer extends MethodVisitor {
|
||||
protected Set<String> descriptorSet;
|
||||
protected HashSet<String> descriptorSet;
|
||||
protected AnnotationIndexer annotationIndexer;
|
||||
|
||||
public MethodIndexer(Set<String> descriptorSet, AnnotationIndexer annotationIndexer) {
|
||||
public MethodIndexer(HashSet<String> descriptorSet, AnnotationIndexer annotationIndexer) {
|
||||
super(Opcodes.ASM5);
|
||||
this.descriptorSet = descriptorSet;
|
||||
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;
|
||||
|
||||
import jd.gui.api.model.Type;
|
||||
import jd.gui.spi.TypeFactory;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
@ -22,7 +26,7 @@ public abstract class AbstractTypeFactoryProvider implements TypeFactory {
|
||||
/**
|
||||
* Initialize "selectors" and "pathPattern" with optional external properties file
|
||||
*/
|
||||
AbstractTypeFactoryProvider() {
|
||||
public AbstractTypeFactoryProvider() {
|
||||
Properties properties = new Properties();
|
||||
Class clazz = this.getClass();
|
||||
|
||||
@ -51,4 +55,153 @@ public abstract class AbstractTypeFactoryProvider implements TypeFactory {
|
||||
return (externalSelectors==null) ? null : externalSelectors.toArray(new String[externalSelectors.size()]);
|
||||
}
|
||||
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 javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
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) {
|
||||
try (InputStream is = entry.getInputStream()) {
|
||||
ClassReader classReader = new ClassReader(is);
|
||||
@ -110,24 +114,24 @@ public class ClassFileTypeFactoryProvider extends AbstractTypeFactoryProvider {
|
||||
}
|
||||
|
||||
static class JavaType implements Type {
|
||||
ClassNode classNode;
|
||||
Container.Entry entry;
|
||||
int access;
|
||||
String name;
|
||||
String shortName;
|
||||
String superName;
|
||||
String outerName;
|
||||
|
||||
String displayTypeName;
|
||||
String displayInnerTypeName;
|
||||
String displayPackageName;
|
||||
protected ClassNode classNode;
|
||||
protected Container.Entry entry;
|
||||
protected int access;
|
||||
protected String name;
|
||||
protected String superName;
|
||||
protected String outerName;
|
||||
|
||||
List<Type> innerTypes;
|
||||
List<Type.Field> fields;
|
||||
List<Type.Method> methods;
|
||||
protected String displayTypeName;
|
||||
protected String displayInnerTypeName;
|
||||
protected String displayPackageName;
|
||||
|
||||
protected List<Type> innerTypes = null;
|
||||
protected List<Type.Field> fields = null;
|
||||
protected List<Type.Method> methods = null;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
JavaType(Container.Entry entry, ClassReader classReader) {
|
||||
protected JavaType(Container.Entry entry, ClassReader classReader) {
|
||||
this.classNode = new ClassNode();
|
||||
this.entry = entry;
|
||||
|
||||
@ -161,27 +165,17 @@ public class ClassFileTypeFactoryProvider extends AbstractTypeFactoryProvider {
|
||||
|
||||
if (lastPackageSeparatorIndex == -1) {
|
||||
this.displayPackageName = "";
|
||||
this.shortName = this.name;
|
||||
this.displayTypeName = (this.outerName != null) ? null : this.shortName;
|
||||
this.displayTypeName = (this.outerName == null) ? this.name : null;
|
||||
} else {
|
||||
this.displayPackageName = this.name.substring(0, lastPackageSeparatorIndex).replace('/', '.');
|
||||
this.shortName = this.name.substring(lastPackageSeparatorIndex+1);
|
||||
this.displayTypeName = (this.outerName != null) ? null : this.shortName;
|
||||
this.displayTypeName = (this.outerName == null) ? this.name.substring(lastPackageSeparatorIndex+1) : null;
|
||||
}
|
||||
|
||||
this.innerTypes = null;
|
||||
this.fields = null;
|
||||
this.methods = null;
|
||||
}
|
||||
|
||||
public int getFlags() { return access; }
|
||||
public String getName() { return name; }
|
||||
public String getShortName() { return shortName; }
|
||||
public String getSuperName() { return superName; }
|
||||
public String getOuterName() { return outerName; }
|
||||
|
||||
public Container.Entry getOuterEntry() { return (outerName==null) ? null : getEntry(outerName); }
|
||||
|
||||
public String getDisplayPackageName() { return displayPackageName; }
|
||||
|
||||
public String getDisplayTypeName() {
|
||||
@ -219,7 +213,7 @@ public class ClassFileTypeFactoryProvider extends AbstractTypeFactoryProvider {
|
||||
}
|
||||
|
||||
public String getDisplayInnerTypeName() { return displayInnerTypeName; }
|
||||
public Icon getIcon() { return getIcon(access); }
|
||||
public Icon getIcon() { return getTypeIcon(access); }
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<Type> getInnerTypes() {
|
||||
@ -266,7 +260,7 @@ public class ClassFileTypeFactoryProvider extends AbstractTypeFactoryProvider {
|
||||
public int getFlags() { return fieldNode.access; }
|
||||
public String getName() { return fieldNode.name; }
|
||||
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 String getName() { return methodNode.name; }
|
||||
public String getDescriptor() { return methodNode.desc; }
|
||||
public Icon getIcon() { return METHOD_ICONS[accessToIndex(methodNode.access)]; }
|
||||
public Icon getIcon() { return getMethodIcon(methodNode.access); }
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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.EarFileLoaderProvider
|
||||
jd.gui.service.fileloader.JarFileLoaderProvider
|
||||
jd.gui.service.fileloader.JavaFileLoaderProvider
|
||||
jd.gui.service.fileloader.LogFileLoaderProvider
|
||||
jd.gui.service.fileloader.WarFileLoaderProvider
|
||||
jd.gui.service.fileloader.ZipFileLoaderProvider
|
||||
|
@ -1,6 +1,7 @@
|
||||
jd.gui.service.indexer.DirectoryIndexerProvider
|
||||
jd.gui.service.indexer.ClassFileIndexerProvider
|
||||
jd.gui.service.indexer.EjbJarXmlFileIndexerProvider
|
||||
jd.gui.service.indexer.JavaFileIndexerProvider
|
||||
jd.gui.service.indexer.MetainfServiceFileIndexerProvider
|
||||
jd.gui.service.indexer.TextFileIndexerProvider
|
||||
jd.gui.service.indexer.WebXmlFileIndexerProvider
|
||||
|
@ -7,7 +7,7 @@ jd.gui.service.treenode.EjbJarXmlFileTreeNodeFactoryProvider
|
||||
jd.gui.service.treenode.FileTreeNodeFactoryProvider
|
||||
jd.gui.service.treenode.HtmlFileTreeNodeFactoryProvider
|
||||
jd.gui.service.treenode.JarFileTreeNodeFactoryProvider
|
||||
#jd.gui.service.treenode.JavaFileTreeNodeFactoryProvider
|
||||
jd.gui.service.treenode.JavaFileTreeNodeFactoryProvider
|
||||
jd.gui.service.treenode.JavascriptFileTreeNodeFactoryProvider
|
||||
jd.gui.service.treenode.JspFileTreeNodeFactoryProvider
|
||||
jd.gui.service.treenode.ManifestFileTreeNodeFactoryProvider
|
||||
|
@ -1 +1,2 @@
|
||||
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 {
|
||||
|
||||
HashMap<String, ClassFilePage.DeclarationData> initDeclarations() {
|
||||
def data = new ClassFilePage.DeclarationData(0, 1, "Test", "test", "I")
|
||||
HashMap<String, ClassFilePage.DeclarationData> declarations = [:]
|
||||
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)
|
||||
@ -43,16 +43,16 @@ class ClassFilePageTest extends GroovyTestCase {
|
||||
TreeMap<Integer, HyperlinkPage.HyperlinkData> initHyperlinks() {
|
||||
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 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", "MAX_VALUE", "I", "Test")))
|
||||
hyperlinks.put(0, new TypePage.HyperlinkReferenceData(0, 1, new TypePage.ReferenceData("java/lang/Integer", "toString", "()Ljava/lang/String;", "Test")))
|
||||
|
||||
return hyperlinks
|
||||
}
|
||||
|
||||
ArrayList<ClassFilePage.StringData> initStrings() {
|
||||
def strings = new ArrayList<ClassFilePage.StringData>()
|
||||
ArrayList<TypePage.StringData> initStrings() {
|
||||
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
|
||||
}
|
||||
|
@ -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>LSTypeIsPackage</key> <false/>
|
||||
</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>
|
||||
<key>CFBundleTypeExtensions</key>
|
||||
<array>
|
||||
|
Loading…
Reference in New Issue
Block a user