mirror of
https://gitee.com/zhangsken/AndroidIDE.git
synced 2026-10-16 07:49:44 +08:00
Added: Show api information of classes, methods and fields
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
# Built application files
|
||||
*.apk
|
||||
*.aar
|
||||
*.ap_
|
||||
*.aab
|
||||
|
||||
# Files for the ART/Dalvik VM
|
||||
*.dex
|
||||
|
||||
# Java class files
|
||||
*.class
|
||||
|
||||
# Generated files
|
||||
bin/
|
||||
gen/
|
||||
out/
|
||||
# Uncomment the following line in case you need and you don't have the release build type files in your app
|
||||
# release/
|
||||
|
||||
# Gradle files
|
||||
.gradle/
|
||||
build/
|
||||
|
||||
# Local configuration file (sdk path, etc)
|
||||
local.properties
|
||||
|
||||
# Proguard folder generated by Eclipse
|
||||
proguard/
|
||||
|
||||
# Log Files
|
||||
*.log
|
||||
|
||||
# Android Studio Navigation editor temp files
|
||||
.navigation/
|
||||
|
||||
# Android Studio captures folder
|
||||
captures/
|
||||
|
||||
# IntelliJ
|
||||
*.iml
|
||||
.idea/workspace.xml
|
||||
.idea/tasks.xml
|
||||
.idea/gradle.xml
|
||||
.idea/assetWizardSettings.xml
|
||||
.idea/dictionaries
|
||||
.idea/libraries
|
||||
# Android Studio 3 in .gitignore file.
|
||||
.idea/caches
|
||||
.idea/modules.xml
|
||||
# Comment next line if keeping position of elements in Navigation Editor is relevant for you
|
||||
.idea/navEditor.xml
|
||||
|
||||
# Keystore files
|
||||
# Uncomment the following lines if you do not want to check your keystore files in.
|
||||
#*.jks
|
||||
#*.keystore
|
||||
|
||||
# External native build folder generated in Android Studio 2.2 and later
|
||||
.externalNativeBuild
|
||||
.cxx/
|
||||
|
||||
# Google Services (e.g. APIs or Firebase)
|
||||
# google-services.json
|
||||
|
||||
# Freeline
|
||||
freeline.py
|
||||
freeline/
|
||||
freeline_project_description.json
|
||||
|
||||
# fastlane
|
||||
fastlane/report.xml
|
||||
fastlane/Preview.html
|
||||
fastlane/screenshots
|
||||
fastlane/test_output
|
||||
fastlane/readme.md
|
||||
|
||||
# Version control
|
||||
vcs.xml
|
||||
|
||||
# lint
|
||||
lint/intermediates/
|
||||
lint/generated/
|
||||
lint/outputs/
|
||||
lint/tmp/
|
||||
# lint/reports/
|
||||
@@ -0,0 +1,29 @@
|
||||
apply plugin: 'com.android.library'
|
||||
|
||||
android {
|
||||
compileSdkVersion rootProject.ext.compileSdk
|
||||
buildToolsVersion rootProject.ext.buildTools
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion rootProject.ext.minSdk
|
||||
targetSdkVersion rootProject.ext.targetSdk
|
||||
versionCode rootProject.ext.versionCode
|
||||
versionName rootProject.ext.versionName
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation 'com.blankj:utilcodex:1.30.6'
|
||||
}
|
||||
Binary file not shown.
Vendored
+17
@@ -0,0 +1,17 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# By default, the flags in this file are appended to flags specified
|
||||
# in /Users/bogdan/Library/Android/sdk/tools/proguard/proguard-android.txt
|
||||
# You can edit the include path and order by changing the proguardFiles
|
||||
# directive in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# Add any project specific keep options here:
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
@@ -0,0 +1 @@
|
||||
<manifest package="com.itsaky.apiinfo"/>
|
||||
@@ -0,0 +1,160 @@
|
||||
package com.itsaky.apiinfo;
|
||||
|
||||
import com.blankj.utilcode.util.FileIOUtils;
|
||||
import com.itsaky.apiinfo.models.ClassInfo;
|
||||
import com.itsaky.apiinfo.models.FieldInfo;
|
||||
import com.itsaky.apiinfo.models.MethodInfo;
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.nodes.Element;
|
||||
import org.jsoup.select.Elements;
|
||||
|
||||
public class ApiInfo {
|
||||
|
||||
private final File versionsXml;
|
||||
|
||||
private boolean read = false;
|
||||
|
||||
private final Map<String, ClassInfo> classInfos;
|
||||
|
||||
public static final String NAME = "name";
|
||||
public static final String SINCE = "since";
|
||||
public static final String DEPRECATED = "deprecated";
|
||||
public static final String REMOVED = "removed";
|
||||
public static final String EXTENDS = "extends";
|
||||
public static final String IMPLEMENTS = "implements";
|
||||
public static final String FIELD = "field";
|
||||
public static final String METHOD = "method";
|
||||
|
||||
public ApiInfo(File versionsXml) {
|
||||
this.versionsXml = versionsXml;
|
||||
this.classInfos = new HashMap<String, ClassInfo>();
|
||||
}
|
||||
|
||||
public boolean hasRead() {
|
||||
return read;
|
||||
}
|
||||
|
||||
public ClassInfo getClassByName(String qualifiedName) {
|
||||
return classInfos.get(qualifiedName);
|
||||
}
|
||||
|
||||
public void readAsync(Runnable onFinish) throws Exception{
|
||||
new Thread(() -> {
|
||||
String contents = FileIOUtils.readFile2String(versionsXml);
|
||||
if(contents != null) {
|
||||
contents = contents.substring(contents.indexOf("<api"));
|
||||
Document doc = Jsoup.parse(contents);
|
||||
Elements classes = doc.getElementsByTag("api").first().getElementsByTag("class");
|
||||
if(classes == null || classes.size() <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for(Element clazz : classes) {
|
||||
ClassInfo info = parseClassInfo(clazz);
|
||||
if(info != null)
|
||||
classInfos.put(info.name, info);
|
||||
}
|
||||
|
||||
read = true;
|
||||
if(onFinish != null)
|
||||
onFinish.run();
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
private ClassInfo parseClassInfo(Element clazz) {
|
||||
if(!clazz.hasAttr(NAME)) return null;
|
||||
ClassInfo info = new ClassInfo();
|
||||
|
||||
info.name = clazz.attr(NAME)
|
||||
.replace("/", ".")
|
||||
.replace("$", ".");
|
||||
|
||||
if(clazz.hasAttr(SINCE)) {
|
||||
info.since = Integer.parseInt(clazz.attr(SINCE));
|
||||
}
|
||||
|
||||
if(clazz.hasAttr(DEPRECATED)) {
|
||||
info.deprecated = Integer.parseInt(clazz.attr(DEPRECATED));
|
||||
}
|
||||
|
||||
if(clazz.hasAttr(REMOVED)) {
|
||||
info.removed = Integer.parseInt(clazz.attr(REMOVED));
|
||||
}
|
||||
|
||||
Elements superClass = clazz.getElementsByTag(EXTENDS);
|
||||
if(superClass != null && superClass.size() == 1) {
|
||||
info.superClass = superClass.first().attr(NAME);
|
||||
}
|
||||
|
||||
Elements interfaces = clazz.getElementsByTag(IMPLEMENTS);
|
||||
if(interfaces != null && interfaces.size() > 0) {
|
||||
for(Element iface : interfaces) {
|
||||
info.interfaces.add(iface.attr(NAME));
|
||||
}
|
||||
}
|
||||
|
||||
Elements fields = clazz.getElementsByTag(FIELD);
|
||||
if(fields != null && fields.size() > 0) {
|
||||
for(Element field : fields) {
|
||||
putField(field, info);
|
||||
}
|
||||
}
|
||||
|
||||
Elements methods = clazz.getElementsByTag(METHOD);
|
||||
if(methods != null && methods.size() > 0) {
|
||||
for(Element method : methods) {
|
||||
putMethod(method, info);
|
||||
}
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
private void putField(Element field, ClassInfo clazz) {
|
||||
if(!field.hasAttr(NAME)) return;
|
||||
FieldInfo info = new FieldInfo();
|
||||
|
||||
info.name = field.attr(NAME);
|
||||
|
||||
if(field.hasAttr(SINCE)) {
|
||||
info.since = Integer.parseInt(field.attr(SINCE));
|
||||
}
|
||||
|
||||
if(field.hasAttr(DEPRECATED)) {
|
||||
info.deprecated = Integer.parseInt(field.attr(DEPRECATED));
|
||||
}
|
||||
|
||||
if(field.hasAttr(REMOVED)) {
|
||||
info.removed = Integer.parseInt(field.attr(REMOVED));
|
||||
}
|
||||
|
||||
clazz.fields.put(info.name, info);
|
||||
}
|
||||
|
||||
private void putMethod(Element method, ClassInfo clazz) {
|
||||
if(!method.hasAttr(NAME)) return;
|
||||
MethodInfo info = new MethodInfo();
|
||||
|
||||
info.name = method.attr(NAME);
|
||||
info.simpleName = info.name.substring(0, info.name.indexOf("("));
|
||||
|
||||
if(method.hasAttr(SINCE)) {
|
||||
info.since = Integer.parseInt(method.attr(SINCE));
|
||||
}
|
||||
|
||||
if(method.hasAttr(DEPRECATED)) {
|
||||
info.deprecated = Integer.parseInt(method.attr(DEPRECATED));
|
||||
}
|
||||
|
||||
if(method.hasAttr(REMOVED)) {
|
||||
info.removed = Integer.parseInt(method.attr(REMOVED));
|
||||
}
|
||||
|
||||
clazz.methods.put(info.name, info);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
package com.itsaky.apiinfo.models;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.eclipse.jdt.core.Signature;
|
||||
import android.os.Environment;
|
||||
import java.io.FileNotFoundException;
|
||||
|
||||
/**
|
||||
* Holds information about a class
|
||||
*/
|
||||
public class ClassInfo extends Info {
|
||||
|
||||
/**
|
||||
* Superclass of this class
|
||||
*/
|
||||
public String superClass;
|
||||
|
||||
/**
|
||||
* Interfaces that this class implements
|
||||
*/
|
||||
public final List<String> interfaces = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Fields of this class
|
||||
*/
|
||||
public final Map<String, FieldInfo> fields = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Methods of this class
|
||||
*/
|
||||
public final Map<String, MethodInfo> methods = new HashMap<>();
|
||||
|
||||
|
||||
/**
|
||||
* Get the field by its simple name
|
||||
*
|
||||
* @param name Name of the field to find
|
||||
*/
|
||||
public FieldInfo getFieldByName(String name) {
|
||||
return fields.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get method by its name and parameter types
|
||||
*
|
||||
* @param name Name of the method to find
|
||||
* @param parameters Parameter types of the method
|
||||
*/
|
||||
public MethodInfo getMethod(String name, String[] parameters) {
|
||||
|
||||
/**
|
||||
* Convert parameter types to their binary version
|
||||
*/
|
||||
final String[] parameterTypes = new String[parameters.length];
|
||||
for(int i=0;i<parameters.length;i++) {
|
||||
String paramType = parameters[i];
|
||||
String binaryParamType = Signature.createTypeSignature(paramType, true /* isResolved */);
|
||||
parameterTypes[i] = binaryParamType;
|
||||
}
|
||||
|
||||
log("Original parameters: \n" + TextUtils.join(", ", parameters) + "\n\nNew parameters:\n" + TextUtils.join(", ", parameterTypes));
|
||||
|
||||
for(Map.Entry<String, MethodInfo> entry : methods.entrySet()) {
|
||||
MethodInfo method = entry.getValue();
|
||||
|
||||
/**
|
||||
* Check if this method's simple name is what we are looking for
|
||||
*/
|
||||
if(method != null
|
||||
&& method.simpleName.trim().equals(name.trim())) {
|
||||
|
||||
/**
|
||||
* Get parameter types of this method
|
||||
* Takes binary representation, returns binary representation
|
||||
*/
|
||||
String[] paramTypes = Signature.getParameterTypes(method.name);
|
||||
|
||||
/**
|
||||
* Join the parameters to check if they are equal
|
||||
* This is just more efficient
|
||||
*/
|
||||
final String params1 = TextUtils.join(",", paramTypes);
|
||||
final String params2 = TextUtils.join(",", parameterTypes);
|
||||
|
||||
|
||||
if(params1.equals(params2)) {
|
||||
|
||||
/**
|
||||
* We found what we were looking for!
|
||||
*/
|
||||
return method;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private BufferedOutputStream os;
|
||||
|
||||
private void log(String msg) {
|
||||
try {
|
||||
if(os == null)
|
||||
os = new BufferedOutputStream(new FileOutputStream(new File(Environment.getExternalStorageDirectory(), "ide_xlog/class_info.txt")));
|
||||
|
||||
os.write(msg.getBytes());
|
||||
os.flush();
|
||||
} catch (Throwable e) {}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.itsaky.apiinfo.models;
|
||||
|
||||
/**
|
||||
* Holds information about a field
|
||||
*
|
||||
* No difference as compared to Info
|
||||
*/
|
||||
public class FieldInfo extends Info {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.itsaky.apiinfo.models;
|
||||
|
||||
/**
|
||||
* Base class for information about a class, method, field
|
||||
*/
|
||||
public abstract class Info {
|
||||
|
||||
/**
|
||||
* Name of this class, method or field
|
||||
*/
|
||||
public String name = "";
|
||||
|
||||
/**
|
||||
* API level in which this info was deprecated
|
||||
*/
|
||||
public int deprecated = -1;
|
||||
|
||||
/**
|
||||
* API level in which this was added
|
||||
*/
|
||||
public int since = -1;
|
||||
|
||||
/**
|
||||
* API level in which this was removed
|
||||
*/
|
||||
public int removed = -1;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.itsaky.apiinfo.models;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Holds information about a method
|
||||
*/
|
||||
public class MethodInfo extends Info {
|
||||
|
||||
/**
|
||||
* In case of a method, the {@link com.itsaky.apiinfo.models.Info#name} contains signature of the method
|
||||
* This field contains the actual simple name
|
||||
*/
|
||||
public String simpleName;
|
||||
|
||||
/**
|
||||
* Parameter types of this method
|
||||
*/
|
||||
public final List<String> parameters = new ArrayList<>();
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,81 @@
|
||||
package org.eclipse.jdt.internal.compiler.ast;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.core.compiler.CharOperation;
|
||||
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public abstract class ASTNode {
|
||||
// storage for internal flags (32 bits) BIT USAGE
|
||||
public final static int Bit1 = 0x1; // return type (operator) | name reference kind (name ref) | add assertion (type decl) | useful empty statement (empty statement)
|
||||
public final static int Bit2 = 0x2; // return type (operator) | name reference kind (name ref) | has local type (type, method, field decl) | if type elided (local)
|
||||
public final static int Bit3 = 0x4; // return type (operator) | name reference kind (name ref) | implicit this (this ref) | is argument(local)
|
||||
public final static int Bit4 = 0x8; // return type (operator) | first assignment to local (name ref,local decl) | undocumented empty block (block, type and method decl)
|
||||
public final static int Bit5 = 0x10; // value for return (expression) | has all method bodies (unit) | supertype ref (type ref) | resolved (field decl)| name ref (yield result value)
|
||||
public final static int Bit6 = 0x20; // depth (name ref, msg) | ignore need cast check (cast expression) | error in signature (method declaration/ initializer) | is recovered (annotation reference)
|
||||
public final static int Bit7 = 0x40; // depth (name ref, msg) | need runtime checkcast (cast expression) | label used (labelStatement) | needFreeReturn (AbstractMethodDeclaration)
|
||||
public final static int Bit8 = 0x80; // depth (name ref, msg) | unsafe cast (cast expression) | is default constructor (constructor declaration) | isElseStatementUnreachable (if statement)
|
||||
public final static int Bit9 = 0x100; // depth (name ref, msg) | operator (operator) | is local type (type decl) | isThenStatementUnreachable (if statement) | can be static
|
||||
public final static int Bit10= 0x200; // depth (name ref, msg) | operator (operator) | is anonymous type (type decl) | is implicit constructor (constructor)
|
||||
public final static int Bit11 = 0x400; // depth (name ref, msg) | operator (operator) | is member type (type decl)
|
||||
public final static int Bit12 = 0x800; // depth (name ref, msg) | operator (operator) | has abstract methods (type decl)
|
||||
public final static int Bit13 = 0x1000; // depth (name ref, msg) | operator (operator) | is secondary type (type decl)
|
||||
public final static int Bit14 = 0x2000; // strictly assigned (reference lhs) | operator (operator) | discard enclosing instance (explicit constr call) | hasBeenGenerated (type decl)
|
||||
public final static int Bit15 = 0x4000; // is unnecessary cast (expression) | is varargs (type ref) | isSubRoutineEscaping (try statement) | superAccess (javadoc allocation expression/javadoc message send/javadoc return statement)
|
||||
public final static int Bit16 = 0x8000; // in javadoc comment (name ref, type ref, msg)
|
||||
public final static int Bit17 = 0x10000; // compound assigned (reference lhs) | unchecked (msg, alloc, explicit constr call)
|
||||
public final static int Bit18 = 0x20000; // non null (expression) | onDemand (import reference)
|
||||
public final static int Bit19 = 0x40000; // didResolve (parameterized qualified type ref/parameterized single type ref) | empty (javadoc return statement) | needReceiverGenericCast (msg/fieldref)
|
||||
public final static int Bit20 = 0x80000; // contains syntax errors (method declaration, type declaration, field declarations, initializer), typeref: <> name ref: lambda capture)
|
||||
public final static int Bit21 = 0x100000; // for all declarations that can contain type references that have type annotations | insideExpressionStatement
|
||||
public final static int Bit22 = 0x200000; // parenthesis count (expression) | used (import reference) shadows outer local (local declarations)
|
||||
public final static int Bit23 = 0x400000; // parenthesis count (expression) | second or later declarator in declaration (local declarations)
|
||||
public final static int Bit24 = 0x800000; // parenthesis count (expression)
|
||||
public final static int Bit25 = 0x1000000; // parenthesis count (expression)
|
||||
public final static int Bit26 = 0x2000000; // parenthesis count (expression)
|
||||
public final static int Bit27 = 0x4000000; // parenthesis count (expression)
|
||||
public final static int Bit28 = 0x8000000; // parenthesis count (expression)
|
||||
public final static int Bit29 = 0x10000000; // parenthesis count (expression)
|
||||
public final static int Bit30 = 0x20000000; // elseif (if statement) | try block exit (try statement) | fall-through (case statement) | ignore no effect assign (expression ref) | needScope (for statement) | isAnySubRoutineEscaping (return statement) | blockExit (synchronized statement)
|
||||
public final static int Bit31 = 0x40000000; // local declaration reachable (local decl) | ignore raw type check (type ref) | discard entire assignment (assignment) | isSynchronized (return statement) | thenExit (if statement)
|
||||
public final static int Bit32 = 0x80000000; // reachable (statement)
|
||||
|
||||
public final static long Bit32L = 0x80000000L;
|
||||
public final static long Bit33L = 0x100000000L;
|
||||
public final static long Bit34L = 0x200000000L;
|
||||
public final static long Bit35L = 0x400000000L;
|
||||
public final static long Bit36L = 0x800000000L;
|
||||
public final static long Bit37L = 0x1000000000L;
|
||||
public final static long Bit38L = 0x2000000000L;
|
||||
public final static long Bit39L = 0x4000000000L;
|
||||
public final static long Bit40L = 0x8000000000L;
|
||||
public final static long Bit41L = 0x10000000000L;
|
||||
public final static long Bit42L = 0x20000000000L;
|
||||
public final static long Bit43L = 0x40000000000L;
|
||||
public final static long Bit44L = 0x80000000000L;
|
||||
public final static long Bit45L = 0x100000000000L;
|
||||
public final static long Bit46L = 0x200000000000L;
|
||||
public final static long Bit47L = 0x400000000000L;
|
||||
public final static long Bit48L = 0x800000000000L;
|
||||
public final static long Bit49L = 0x1000000000000L;
|
||||
public final static long Bit50L = 0x2000000000000L;
|
||||
public final static long Bit51L = 0x4000000000000L;
|
||||
public final static long Bit52L = 0x8000000000000L;
|
||||
public final static long Bit53L = 0x10000000000000L;
|
||||
public final static long Bit54L = 0x20000000000000L;
|
||||
public final static long Bit55L = 0x40000000000000L;
|
||||
public final static long Bit56L = 0x80000000000000L;
|
||||
public final static long Bit57L = 0x100000000000000L;
|
||||
public final static long Bit58L = 0x200000000000000L;
|
||||
public final static long Bit59L = 0x400000000000000L;
|
||||
public final static long Bit60L = 0x800000000000000L;
|
||||
public final static long Bit61L = 0x1000000000000000L;
|
||||
public final static long Bit62L = 0x2000000000000000L;
|
||||
public final static long Bit63L = 0x4000000000000000L;
|
||||
public final static long Bit64L = 0x8000000000000000L;
|
||||
}
|
||||
+218
@@ -0,0 +1,218 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2000, 2020 IBM Corporation and others.
|
||||
*
|
||||
* This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License 2.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
* Jesper S Moller - Contributions for
|
||||
* Bug 405066 - [1.8][compiler][codegen] Implement code generation infrastructure for JSR335
|
||||
* Bug 406982 - [1.8][compiler] Generation of MethodParameters Attribute in classfile
|
||||
* Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for
|
||||
* Bug 405104 - [1.8][compiler][codegen] Implement support for serializeable lambdas
|
||||
*******************************************************************************/
|
||||
package org.eclipse.jdt.internal.compiler.classfmt;
|
||||
|
||||
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
|
||||
|
||||
public final class ClassFileConstants {
|
||||
|
||||
int AccDefault = 0;
|
||||
/*
|
||||
* Modifiers
|
||||
*/
|
||||
int AccPublic = 0x0001;
|
||||
int AccPrivate = 0x0002;
|
||||
int AccProtected = 0x0004;
|
||||
int AccStatic = 0x0008;
|
||||
int AccFinal = 0x0010;
|
||||
int AccSynchronized = 0x0020;
|
||||
int AccVolatile = 0x0040;
|
||||
int AccBridge = 0x0040;
|
||||
int AccTransient = 0x0080;
|
||||
int AccVarargs = 0x0080;
|
||||
int AccNative = 0x0100;
|
||||
int AccInterface = 0x0200;
|
||||
int AccAbstract = 0x0400;
|
||||
int AccStrictfp = 0x0800;
|
||||
int AccSynthetic = 0x1000;
|
||||
int AccAnnotation = 0x2000;
|
||||
int AccEnum = 0x4000;
|
||||
int AccModule = 0x8000;
|
||||
|
||||
/**
|
||||
* From classfile version 52 (compliance 1.8 up), meaning that a formal parameter is mandated
|
||||
* by a language specification, so all compilers for the language must emit it.
|
||||
*/
|
||||
int AccMandated = 0x8000;
|
||||
|
||||
/**
|
||||
* Flags in module declaration - since java9
|
||||
*/
|
||||
int ACC_OPEN = 0x0020;
|
||||
int ACC_TRANSITIVE = 0x0020;
|
||||
int ACC_STATIC_PHASE = 0x0040;
|
||||
int ACC_SYNTHETIC = 0x1000;
|
||||
|
||||
/**
|
||||
* Other VM flags.
|
||||
*/
|
||||
int AccSuper = 0x0020;
|
||||
|
||||
/**
|
||||
* Extra flags for types and members attributes (not from the JVMS, should have been defined in ExtraCompilerModifiers).
|
||||
*/
|
||||
int AccAnnotationDefault = ASTNode.Bit18; // indicate presence of an attribute "DefaultValue" (annotation method)
|
||||
int AccDeprecated = ASTNode.Bit21; // indicate presence of an attribute "Deprecated"
|
||||
|
||||
int Utf8Tag = 1;
|
||||
int IntegerTag = 3;
|
||||
int FloatTag = 4;
|
||||
int LongTag = 5;
|
||||
int DoubleTag = 6;
|
||||
int ClassTag = 7;
|
||||
int StringTag = 8;
|
||||
int FieldRefTag = 9;
|
||||
int MethodRefTag = 10;
|
||||
int InterfaceMethodRefTag = 11;
|
||||
int NameAndTypeTag = 12;
|
||||
int MethodHandleTag = 15;
|
||||
int MethodTypeTag = 16;
|
||||
int DynamicTag = 17;
|
||||
int InvokeDynamicTag = 18;
|
||||
int ModuleTag = 19;
|
||||
int PackageTag = 20;
|
||||
|
||||
int ConstantMethodRefFixedSize = 5;
|
||||
int ConstantClassFixedSize = 3;
|
||||
int ConstantDoubleFixedSize = 9;
|
||||
int ConstantFieldRefFixedSize = 5;
|
||||
int ConstantFloatFixedSize = 5;
|
||||
int ConstantIntegerFixedSize = 5;
|
||||
int ConstantInterfaceMethodRefFixedSize = 5;
|
||||
int ConstantLongFixedSize = 9;
|
||||
int ConstantStringFixedSize = 3;
|
||||
int ConstantUtf8FixedSize = 3;
|
||||
int ConstantNameAndTypeFixedSize = 5;
|
||||
int ConstantMethodHandleFixedSize = 4;
|
||||
int ConstantMethodTypeFixedSize = 3;
|
||||
int ConstantDynamicFixedSize = 5;
|
||||
int ConstantInvokeDynamicFixedSize = 5;
|
||||
int ConstantModuleFixedSize = 3;
|
||||
int ConstantPackageFixedSize = 3;
|
||||
|
||||
// JVMS 4.4.8
|
||||
int MethodHandleRefKindGetField = 1;
|
||||
int MethodHandleRefKindGetStatic = 2;
|
||||
int MethodHandleRefKindPutField = 3;
|
||||
int MethodHandleRefKindPutStatic = 4;
|
||||
int MethodHandleRefKindInvokeVirtual = 5;
|
||||
int MethodHandleRefKindInvokeStatic = 6;
|
||||
int MethodHandleRefKindInvokeSpecial = 7;
|
||||
int MethodHandleRefKindNewInvokeSpecial = 8;
|
||||
int MethodHandleRefKindInvokeInterface = 9;
|
||||
|
||||
static int MAJOR_VERSION_1_1 = 45;
|
||||
static int MAJOR_VERSION_1_2 = 46;
|
||||
static int MAJOR_VERSION_1_3 = 47;
|
||||
static int MAJOR_VERSION_1_4 = 48;
|
||||
static int MAJOR_VERSION_1_5 = 49;
|
||||
static int MAJOR_VERSION_1_6 = 50;
|
||||
static int MAJOR_VERSION_1_7 = 51;
|
||||
static int MAJOR_VERSION_1_8 = 52;
|
||||
static int MAJOR_VERSION_9 = 53;
|
||||
static int MAJOR_VERSION_10 = 54;
|
||||
static int MAJOR_VERSION_11 = 55;
|
||||
static int MAJOR_VERSION_12 = 56;
|
||||
static int MAJOR_VERSION_13 = 57;
|
||||
static int MAJOR_VERSION_14 = 58;
|
||||
static int MAJOR_VERSION_15 = 59;
|
||||
static int MAJOR_VERSION_16 = 60;
|
||||
|
||||
static int MAJOR_VERSION_0 = 44;
|
||||
static int MAJOR_LATEST_VERSION = MAJOR_VERSION_16;
|
||||
|
||||
static int MINOR_VERSION_0 = 0;
|
||||
static int MINOR_VERSION_1 = 1;
|
||||
static int MINOR_VERSION_2 = 2;
|
||||
static int MINOR_VERSION_3 = 3;
|
||||
static int MINOR_VERSION_4 = 4;
|
||||
static int MINOR_VERSION_PREVIEW = 0xffff;
|
||||
|
||||
// JDK 1.1 -> 9, comparable value allowing to check both major/minor version at once 1.4.1 > 1.4.0
|
||||
// 16 unsigned bits for major, then 16 bits for minor
|
||||
public static long JDK1_1 = ((long)MAJOR_VERSION_1_1 << 16) + MINOR_VERSION_3; // 1.1. is 45.3
|
||||
public static long JDK1_2 = ((long)MAJOR_VERSION_1_2 << 16) + MINOR_VERSION_0;
|
||||
public static long JDK1_3 = ((long)MAJOR_VERSION_1_3 << 16) + MINOR_VERSION_0;
|
||||
public static long JDK1_4 = ((long)MAJOR_VERSION_1_4 << 16) + MINOR_VERSION_0;
|
||||
public static long JDK1_5 = ((long)MAJOR_VERSION_1_5 << 16) + MINOR_VERSION_0;
|
||||
public static long JDK1_6 = ((long)MAJOR_VERSION_1_6 << 16) + MINOR_VERSION_0;
|
||||
public static long JDK1_7 = ((long)MAJOR_VERSION_1_7 << 16) + MINOR_VERSION_0;
|
||||
public static long JDK1_8 = ((long)MAJOR_VERSION_1_8 << 16) + MINOR_VERSION_0;
|
||||
public static long JDK9 = ((long)MAJOR_VERSION_9 << 16) + MINOR_VERSION_0;
|
||||
public static long JDK10 = ((long)MAJOR_VERSION_10 << 16) + MINOR_VERSION_0;
|
||||
public static long JDK11 = ((long)MAJOR_VERSION_11 << 16) + MINOR_VERSION_0;
|
||||
public static long JDK12 = ((long)MAJOR_VERSION_12 << 16) + MINOR_VERSION_0;
|
||||
public static long JDK13 = ((long)MAJOR_VERSION_13 << 16) + MINOR_VERSION_0;
|
||||
public static long JDK14 = ((long)MAJOR_VERSION_14 << 16) + MINOR_VERSION_0;
|
||||
public static long JDK15 = ((long)MAJOR_VERSION_15 << 16) + MINOR_VERSION_0;
|
||||
public static long JDK16 = ((long)MAJOR_VERSION_16 << 16) + MINOR_VERSION_0;
|
||||
|
||||
public static long getLatestJDKLevel() {
|
||||
return ((long)MAJOR_LATEST_VERSION << 16) + MINOR_VERSION_0;
|
||||
}
|
||||
|
||||
/**
|
||||
* As we move away from declaring every compliance level explicitly (such as JDK11, JDK12 etc.),
|
||||
* this method can be used to compute the compliance level on the fly for a given Java major version.
|
||||
*
|
||||
* @param major Java major version
|
||||
* @return the compliance level for the given Java version
|
||||
*/
|
||||
public static long getComplianceLevelForJavaVersion(int major) {
|
||||
switch(major) {
|
||||
case 45: // MAJOR_VERSION_1_1
|
||||
return ((long)MAJOR_VERSION_1_1 << 16) + MINOR_VERSION_3;
|
||||
default:
|
||||
major = Math.min(major, MAJOR_LATEST_VERSION);
|
||||
return ((long)major << 16) + MINOR_VERSION_0;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* cldc1.1 is 45.3, but we modify it to be different from JDK1_1.
|
||||
* In the code gen, we will generate the same target value as JDK1_1
|
||||
*/
|
||||
long CLDC_1_1 = ((long)MAJOR_VERSION_1_1 << 16) + MINOR_VERSION_4;
|
||||
|
||||
// jdk level used to denote future releases: optional behavior is not enabled for now, but may become so. In order to enable these,
|
||||
// search for references to this constant, and change it to one of the official JDT constants above.
|
||||
public static long JDK_DEFERRED = Long.MAX_VALUE;
|
||||
|
||||
int INT_ARRAY = 10;
|
||||
int BYTE_ARRAY = 8;
|
||||
int BOOLEAN_ARRAY = 4;
|
||||
int SHORT_ARRAY = 9;
|
||||
int CHAR_ARRAY = 5;
|
||||
int LONG_ARRAY = 11;
|
||||
int FLOAT_ARRAY = 6;
|
||||
int DOUBLE_ARRAY = 7;
|
||||
|
||||
// Debug attributes
|
||||
int ATTR_SOURCE = 0x1; // SourceFileAttribute
|
||||
int ATTR_LINES = 0x2; // LineNumberAttribute
|
||||
int ATTR_VARS = 0x4; // LocalVariableTableAttribute
|
||||
int ATTR_STACK_MAP_TABLE = 0x8; // Stack map table attribute
|
||||
int ATTR_STACK_MAP = 0x10; // Stack map attribute: cldc
|
||||
int ATTR_TYPE_ANNOTATION = 0x20; // type annotation attribute (jsr 308)
|
||||
int ATTR_METHOD_PARAMETERS = 0x40; // method parameters attribute (jep 118)
|
||||
|
||||
// See java.lang.invoke.LambdaMetafactory constants - option bitflags when calling altMetaFactory()
|
||||
int FLAG_SERIALIZABLE = 0x01;
|
||||
int FLAG_MARKERS = 0x02;
|
||||
int FLAG_BRIDGES = 0x04;
|
||||
}
|
||||
@@ -0,0 +1,646 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2005, 2020 IBM Corporation and others.
|
||||
*
|
||||
* This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License 2.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
* David Foerster - patch for toUpperCase as described in https://bugs.eclipse.org/bugs/show_bug.cgi?id=153125
|
||||
*******************************************************************************/
|
||||
package org.eclipse.jdt.internal.compiler.parser;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
|
||||
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
|
||||
|
||||
public class ScannerHelper {
|
||||
|
||||
public final static long[] Bits = {
|
||||
ASTNode.Bit1, ASTNode.Bit2, ASTNode.Bit3, ASTNode.Bit4, ASTNode.Bit5, ASTNode.Bit6,
|
||||
ASTNode.Bit7, ASTNode.Bit8, ASTNode.Bit9, ASTNode.Bit10, ASTNode.Bit11, ASTNode.Bit12,
|
||||
ASTNode.Bit13, ASTNode.Bit14, ASTNode.Bit15, ASTNode.Bit16, ASTNode.Bit17, ASTNode.Bit18,
|
||||
ASTNode.Bit19, ASTNode.Bit20, ASTNode.Bit21, ASTNode.Bit22, ASTNode.Bit23, ASTNode.Bit24,
|
||||
ASTNode.Bit25, ASTNode.Bit26, ASTNode.Bit27, ASTNode.Bit28, ASTNode.Bit29, ASTNode.Bit30,
|
||||
ASTNode.Bit31, ASTNode.Bit32L, ASTNode.Bit33L, ASTNode.Bit34L, ASTNode.Bit35L, ASTNode.Bit36L,
|
||||
ASTNode.Bit37L, ASTNode.Bit38L, ASTNode.Bit39L, ASTNode.Bit40L, ASTNode.Bit41L, ASTNode.Bit42L,
|
||||
ASTNode.Bit43L, ASTNode.Bit44L, ASTNode.Bit45L, ASTNode.Bit46L, ASTNode.Bit47L, ASTNode.Bit48L,
|
||||
ASTNode.Bit49L, ASTNode.Bit50L, ASTNode.Bit51L, ASTNode.Bit52L, ASTNode.Bit53L, ASTNode.Bit54L,
|
||||
ASTNode.Bit55L, ASTNode.Bit56L, ASTNode.Bit57L, ASTNode.Bit58L, ASTNode.Bit59L, ASTNode.Bit60L,
|
||||
ASTNode.Bit61L, ASTNode.Bit62L, ASTNode.Bit63L, ASTNode.Bit64L,
|
||||
};
|
||||
|
||||
private static final int START_INDEX = 0;
|
||||
private static final int PART_INDEX = 1;
|
||||
|
||||
private static long[][][] Tables;
|
||||
private static long[][][] Tables7;
|
||||
private static long[][][] Tables8;
|
||||
private static long[][][] Tables9;
|
||||
private static long[][][] Tables11;
|
||||
private static long[][][] Tables12;
|
||||
private static long[][][] Tables13;
|
||||
private static long[][][] Tables15;
|
||||
|
||||
public final static int MAX_OBVIOUS = 128;
|
||||
public final static int[] OBVIOUS_IDENT_CHAR_NATURES = new int[MAX_OBVIOUS];
|
||||
|
||||
public final static int C_JLS_SPACE = ASTNode.Bit9;
|
||||
public final static int C_SPECIAL = ASTNode.Bit8;
|
||||
public final static int C_IDENT_START = ASTNode.Bit7;
|
||||
public final static int C_UPPER_LETTER = ASTNode.Bit6;
|
||||
public final static int C_LOWER_LETTER = ASTNode.Bit5;
|
||||
public final static int C_IDENT_PART = ASTNode.Bit4;
|
||||
public final static int C_DIGIT = ASTNode.Bit3;
|
||||
public final static int C_SEPARATOR = ASTNode.Bit2;
|
||||
public final static int C_SPACE = ASTNode.Bit1;
|
||||
|
||||
static {
|
||||
OBVIOUS_IDENT_CHAR_NATURES[0] = C_IDENT_PART;
|
||||
OBVIOUS_IDENT_CHAR_NATURES[1] = C_IDENT_PART;
|
||||
OBVIOUS_IDENT_CHAR_NATURES[2] = C_IDENT_PART;
|
||||
OBVIOUS_IDENT_CHAR_NATURES[3] = C_IDENT_PART;
|
||||
OBVIOUS_IDENT_CHAR_NATURES[4] = C_IDENT_PART;
|
||||
OBVIOUS_IDENT_CHAR_NATURES[5] = C_IDENT_PART;
|
||||
OBVIOUS_IDENT_CHAR_NATURES[6] = C_IDENT_PART;
|
||||
OBVIOUS_IDENT_CHAR_NATURES[7] = C_IDENT_PART;
|
||||
OBVIOUS_IDENT_CHAR_NATURES[8] = C_IDENT_PART;
|
||||
OBVIOUS_IDENT_CHAR_NATURES[14] = C_IDENT_PART;
|
||||
OBVIOUS_IDENT_CHAR_NATURES[15] = C_IDENT_PART;
|
||||
OBVIOUS_IDENT_CHAR_NATURES[16] = C_IDENT_PART;
|
||||
OBVIOUS_IDENT_CHAR_NATURES[17] = C_IDENT_PART;
|
||||
OBVIOUS_IDENT_CHAR_NATURES[18] = C_IDENT_PART;
|
||||
OBVIOUS_IDENT_CHAR_NATURES[19] = C_IDENT_PART;
|
||||
OBVIOUS_IDENT_CHAR_NATURES[20] = C_IDENT_PART;
|
||||
OBVIOUS_IDENT_CHAR_NATURES[21] = C_IDENT_PART;
|
||||
OBVIOUS_IDENT_CHAR_NATURES[22] = C_IDENT_PART;
|
||||
OBVIOUS_IDENT_CHAR_NATURES[23] = C_IDENT_PART;
|
||||
OBVIOUS_IDENT_CHAR_NATURES[24] = C_IDENT_PART;
|
||||
OBVIOUS_IDENT_CHAR_NATURES[25] = C_IDENT_PART;
|
||||
OBVIOUS_IDENT_CHAR_NATURES[26] = C_IDENT_PART;
|
||||
OBVIOUS_IDENT_CHAR_NATURES[27] = C_IDENT_PART;
|
||||
OBVIOUS_IDENT_CHAR_NATURES[127] = C_IDENT_PART;
|
||||
|
||||
for (int i = '0'; i <= '9'; i++)
|
||||
OBVIOUS_IDENT_CHAR_NATURES[i] = C_DIGIT | C_IDENT_PART;
|
||||
|
||||
for (int i = 'a'; i <= 'z'; i++)
|
||||
OBVIOUS_IDENT_CHAR_NATURES[i] = C_LOWER_LETTER | C_IDENT_PART | C_IDENT_START;
|
||||
for (int i = 'A'; i <= 'Z'; i++)
|
||||
OBVIOUS_IDENT_CHAR_NATURES[i] = C_UPPER_LETTER | C_IDENT_PART | C_IDENT_START;
|
||||
|
||||
OBVIOUS_IDENT_CHAR_NATURES['_'] = C_SPECIAL | C_IDENT_PART | C_IDENT_START;
|
||||
OBVIOUS_IDENT_CHAR_NATURES['$'] = C_SPECIAL | C_IDENT_PART | C_IDENT_START;
|
||||
|
||||
OBVIOUS_IDENT_CHAR_NATURES[9] = C_SPACE | C_JLS_SPACE; // \ u0009: HORIZONTAL TABULATION
|
||||
OBVIOUS_IDENT_CHAR_NATURES[10] = C_SPACE | C_JLS_SPACE; // \ u000a: LINE FEED
|
||||
OBVIOUS_IDENT_CHAR_NATURES[11] = C_SPACE;
|
||||
OBVIOUS_IDENT_CHAR_NATURES[12] = C_SPACE | C_JLS_SPACE; // \ u000c: FORM FEED
|
||||
OBVIOUS_IDENT_CHAR_NATURES[13] = C_SPACE | C_JLS_SPACE; // \ u000d: CARRIAGE RETURN
|
||||
OBVIOUS_IDENT_CHAR_NATURES[28] = C_SPACE;
|
||||
OBVIOUS_IDENT_CHAR_NATURES[29] = C_SPACE;
|
||||
OBVIOUS_IDENT_CHAR_NATURES[30] = C_SPACE;
|
||||
OBVIOUS_IDENT_CHAR_NATURES[31] = C_SPACE;
|
||||
OBVIOUS_IDENT_CHAR_NATURES[32] = C_SPACE | C_JLS_SPACE; // \ u0020: SPACE
|
||||
|
||||
OBVIOUS_IDENT_CHAR_NATURES['.'] = C_SEPARATOR;
|
||||
OBVIOUS_IDENT_CHAR_NATURES[':'] = C_SEPARATOR;
|
||||
OBVIOUS_IDENT_CHAR_NATURES[';'] = C_SEPARATOR;
|
||||
OBVIOUS_IDENT_CHAR_NATURES[','] = C_SEPARATOR;
|
||||
OBVIOUS_IDENT_CHAR_NATURES['['] = C_SEPARATOR;
|
||||
OBVIOUS_IDENT_CHAR_NATURES[']'] = C_SEPARATOR;
|
||||
OBVIOUS_IDENT_CHAR_NATURES['('] = C_SEPARATOR;
|
||||
OBVIOUS_IDENT_CHAR_NATURES[')'] = C_SEPARATOR;
|
||||
OBVIOUS_IDENT_CHAR_NATURES['{'] = C_SEPARATOR;
|
||||
OBVIOUS_IDENT_CHAR_NATURES['}'] = C_SEPARATOR;
|
||||
OBVIOUS_IDENT_CHAR_NATURES['+'] = C_SEPARATOR;
|
||||
OBVIOUS_IDENT_CHAR_NATURES['-'] = C_SEPARATOR;
|
||||
OBVIOUS_IDENT_CHAR_NATURES['*'] = C_SEPARATOR;
|
||||
OBVIOUS_IDENT_CHAR_NATURES['/'] = C_SEPARATOR;
|
||||
OBVIOUS_IDENT_CHAR_NATURES['='] = C_SEPARATOR;
|
||||
OBVIOUS_IDENT_CHAR_NATURES['&'] = C_SEPARATOR;
|
||||
OBVIOUS_IDENT_CHAR_NATURES['|'] = C_SEPARATOR;
|
||||
OBVIOUS_IDENT_CHAR_NATURES['?'] = C_SEPARATOR;
|
||||
OBVIOUS_IDENT_CHAR_NATURES['<'] = C_SEPARATOR;
|
||||
OBVIOUS_IDENT_CHAR_NATURES['>'] = C_SEPARATOR;
|
||||
OBVIOUS_IDENT_CHAR_NATURES['!'] = C_SEPARATOR;
|
||||
OBVIOUS_IDENT_CHAR_NATURES['%'] = C_SEPARATOR;
|
||||
OBVIOUS_IDENT_CHAR_NATURES['^'] = C_SEPARATOR;
|
||||
OBVIOUS_IDENT_CHAR_NATURES['~'] = C_SEPARATOR;
|
||||
OBVIOUS_IDENT_CHAR_NATURES['"'] = C_SEPARATOR;
|
||||
OBVIOUS_IDENT_CHAR_NATURES['\''] = C_SEPARATOR;
|
||||
}
|
||||
static void initializeTable() {
|
||||
Tables = initializeTables("unicode"); //$NON-NLS-1$
|
||||
}
|
||||
static void initializeTable17() {
|
||||
Tables7 = initializeTables("unicode6"); //$NON-NLS-1$
|
||||
}
|
||||
static void initializeTable18() {
|
||||
Tables8 = initializeTables("unicode6_2"); //$NON-NLS-1$
|
||||
}
|
||||
static void initializeTable19() {
|
||||
Tables9 = initializeTables("unicode8"); //$NON-NLS-1$
|
||||
}
|
||||
static void initializeTableJava11() {
|
||||
Tables11 = initializeTables("unicode10"); //$NON-NLS-1$
|
||||
}
|
||||
static void initializeTableJava12() {
|
||||
Tables12 = initializeTables("unicode11"); //$NON-NLS-1$
|
||||
}
|
||||
static void initializeTableJava13() {
|
||||
Tables13 = initializeTables("unicode12_1"); //$NON-NLS-1$
|
||||
}
|
||||
static void initializeTableJava15() {
|
||||
Tables15 = initializeTables13andPlus("unicode13"); //$NON-NLS-1$
|
||||
}
|
||||
static long[][][] initializeTables(String unicode_path) {
|
||||
long[][][] tempTable = new long[2][][];
|
||||
tempTable[START_INDEX] = new long[3][];
|
||||
tempTable[PART_INDEX] = new long[4][];
|
||||
try (DataInputStream inputStream = new DataInputStream(new BufferedInputStream(ScannerHelper.class.getResourceAsStream(unicode_path + "/start0.rsc")))) { //$NON-NLS-1$
|
||||
long[] readValues = new long[1024];
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
readValues[i] = inputStream.readLong();
|
||||
}
|
||||
tempTable[START_INDEX][0] = readValues;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
try (DataInputStream inputStream = new DataInputStream(new BufferedInputStream(ScannerHelper.class.getResourceAsStream(unicode_path + "/start1.rsc")))) { //$NON-NLS-1$
|
||||
long[] readValues = new long[1024];
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
readValues[i] = inputStream.readLong();
|
||||
}
|
||||
tempTable[START_INDEX][1] = readValues;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
try (DataInputStream inputStream = new DataInputStream(new BufferedInputStream(ScannerHelper.class.getResourceAsStream(unicode_path + "/start2.rsc")))) { //$NON-NLS-1$
|
||||
long[] readValues = new long[1024];
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
readValues[i] = inputStream.readLong();
|
||||
}
|
||||
tempTable[START_INDEX][2] = readValues;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
try (DataInputStream inputStream = new DataInputStream(new BufferedInputStream(ScannerHelper.class.getResourceAsStream(unicode_path + "/part0.rsc")))) { //$NON-NLS-1$
|
||||
long[] readValues = new long[1024];
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
readValues[i] = inputStream.readLong();
|
||||
}
|
||||
tempTable[PART_INDEX][0] = readValues;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
try (DataInputStream inputStream = new DataInputStream(new BufferedInputStream(ScannerHelper.class.getResourceAsStream(unicode_path + "/part1.rsc")))) { //$NON-NLS-1$
|
||||
long[] readValues = new long[1024];
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
readValues[i] = inputStream.readLong();
|
||||
}
|
||||
tempTable[PART_INDEX][1] = readValues;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
try (DataInputStream inputStream = new DataInputStream(new BufferedInputStream(ScannerHelper.class.getResourceAsStream(unicode_path + "/part2.rsc")))) { //$NON-NLS-1$
|
||||
long[] readValues = new long[1024];
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
readValues[i] = inputStream.readLong();
|
||||
}
|
||||
tempTable[PART_INDEX][2] = readValues;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
try (DataInputStream inputStream = new DataInputStream(new BufferedInputStream(ScannerHelper.class.getResourceAsStream(unicode_path + "/part14.rsc")))) { //$NON-NLS-1$
|
||||
long[] readValues = new long[1024];
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
readValues[i] = inputStream.readLong();
|
||||
}
|
||||
tempTable[PART_INDEX][3] = readValues;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return tempTable;
|
||||
}
|
||||
static long[][][] initializeTables13andPlus(String unicode_path) {
|
||||
long[][][] tempTable = new long[2][][];
|
||||
tempTable[START_INDEX] = new long[4][];
|
||||
tempTable[PART_INDEX] = new long[5][];
|
||||
try (DataInputStream inputStream = new DataInputStream(new BufferedInputStream(ScannerHelper.class.getResourceAsStream(unicode_path + "/start0.rsc")))) { //$NON-NLS-1$
|
||||
long[] readValues = new long[1024];
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
readValues[i] = inputStream.readLong();
|
||||
}
|
||||
tempTable[START_INDEX][0] = readValues;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
try (DataInputStream inputStream = new DataInputStream(new BufferedInputStream(ScannerHelper.class.getResourceAsStream(unicode_path + "/start1.rsc")))) { //$NON-NLS-1$
|
||||
long[] readValues = new long[1024];
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
readValues[i] = inputStream.readLong();
|
||||
}
|
||||
tempTable[START_INDEX][1] = readValues;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
try (DataInputStream inputStream = new DataInputStream(new BufferedInputStream(ScannerHelper.class.getResourceAsStream(unicode_path + "/start2.rsc")))) { //$NON-NLS-1$
|
||||
long[] readValues = new long[1024];
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
readValues[i] = inputStream.readLong();
|
||||
}
|
||||
tempTable[START_INDEX][2] = readValues;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
try (DataInputStream inputStream = new DataInputStream(new BufferedInputStream(ScannerHelper.class.getResourceAsStream(unicode_path + "/start3.rsc")))) { //$NON-NLS-1$
|
||||
long[] readValues = new long[1024];
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
readValues[i] = inputStream.readLong();
|
||||
}
|
||||
tempTable[START_INDEX][3] = readValues;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
try (DataInputStream inputStream = new DataInputStream(new BufferedInputStream(ScannerHelper.class.getResourceAsStream(unicode_path + "/part0.rsc")))) { //$NON-NLS-1$
|
||||
long[] readValues = new long[1024];
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
readValues[i] = inputStream.readLong();
|
||||
}
|
||||
tempTable[PART_INDEX][0] = readValues;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
try (DataInputStream inputStream = new DataInputStream(new BufferedInputStream(ScannerHelper.class.getResourceAsStream(unicode_path + "/part1.rsc")))) { //$NON-NLS-1$
|
||||
long[] readValues = new long[1024];
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
readValues[i] = inputStream.readLong();
|
||||
}
|
||||
tempTable[PART_INDEX][1] = readValues;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
try (DataInputStream inputStream = new DataInputStream(new BufferedInputStream(ScannerHelper.class.getResourceAsStream(unicode_path + "/part2.rsc")))) { //$NON-NLS-1$
|
||||
long[] readValues = new long[1024];
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
readValues[i] = inputStream.readLong();
|
||||
}
|
||||
tempTable[PART_INDEX][2] = readValues;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
try (DataInputStream inputStream = new DataInputStream(new BufferedInputStream(ScannerHelper.class.getResourceAsStream(unicode_path + "/part3.rsc")))) { //$NON-NLS-1$
|
||||
long[] readValues = new long[1024];
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
readValues[i] = inputStream.readLong();
|
||||
}
|
||||
tempTable[PART_INDEX][3] = readValues;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
try (DataInputStream inputStream = new DataInputStream(new BufferedInputStream(ScannerHelper.class.getResourceAsStream(unicode_path + "/part14.rsc")))) { //$NON-NLS-1$
|
||||
long[] readValues = new long[1024];
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
readValues[i] = inputStream.readLong();
|
||||
}
|
||||
tempTable[PART_INDEX][4] = readValues;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return tempTable;
|
||||
}
|
||||
private final static boolean isBitSet(long[] values, int i) {
|
||||
try {
|
||||
return (values[i / 64] & Bits[i % 64]) != 0;
|
||||
} catch (NullPointerException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public static boolean isJavaIdentifierPart(char c) {
|
||||
if (c < MAX_OBVIOUS) {
|
||||
return (ScannerHelper.OBVIOUS_IDENT_CHAR_NATURES[c] & ScannerHelper.C_IDENT_PART) != 0;
|
||||
}
|
||||
return Character.isJavaIdentifierPart(c);
|
||||
}
|
||||
public static boolean isJavaIdentifierPart(long complianceLevel, char c) {
|
||||
if (c < MAX_OBVIOUS) {
|
||||
return (ScannerHelper.OBVIOUS_IDENT_CHAR_NATURES[c] & ScannerHelper.C_IDENT_PART) != 0;
|
||||
}
|
||||
return isJavaIdentifierPart(complianceLevel, (int) c);
|
||||
}
|
||||
private static boolean isJavaIdentifierPart0(int codePoint, long[][][] tables) {
|
||||
return isJavaIdentifierPart0(codePoint, tables, false);
|
||||
}
|
||||
private static boolean isJavaIdentifierPart0(int codePoint, long[][][] tables, boolean isJava15orAbove) {
|
||||
switch((codePoint & 0x1F0000) >> 16) {
|
||||
case 0 :
|
||||
return isBitSet(tables[PART_INDEX][0], codePoint & 0xFFFF);
|
||||
case 1 :
|
||||
return isBitSet(tables[PART_INDEX][1], codePoint & 0xFFFF);
|
||||
case 2 :
|
||||
return isBitSet(tables[PART_INDEX][2], codePoint & 0xFFFF);
|
||||
case 3 :
|
||||
if (isJava15orAbove) {
|
||||
return isBitSet(tables[PART_INDEX][3], codePoint & 0xFFFF);
|
||||
}
|
||||
return false;
|
||||
case 14 :
|
||||
if (isJava15orAbove) {
|
||||
return isBitSet(tables[PART_INDEX][4], codePoint & 0xFFFF);
|
||||
}
|
||||
return isBitSet(tables[PART_INDEX][3], codePoint & 0xFFFF);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public static boolean isJavaIdentifierPart(long complianceLevel, int codePoint) {
|
||||
if (complianceLevel <= ClassFileConstants.JDK1_6) {
|
||||
if (Tables == null) {
|
||||
initializeTable();
|
||||
}
|
||||
return isJavaIdentifierPart0(codePoint, Tables);
|
||||
} else if (complianceLevel <= ClassFileConstants.JDK1_7) {
|
||||
// java 7 supports Unicode 6
|
||||
if (Tables7 == null) {
|
||||
initializeTable17();
|
||||
}
|
||||
return isJavaIdentifierPart0(codePoint, Tables7);
|
||||
} else if (complianceLevel <= ClassFileConstants.JDK1_8) {
|
||||
// java 8 supports Unicode 6.2
|
||||
if (Tables8 == null) {
|
||||
initializeTable18();
|
||||
}
|
||||
return isJavaIdentifierPart0(codePoint, Tables8);
|
||||
} else if (complianceLevel <= ClassFileConstants.JDK10) {
|
||||
// java 9/10 supports Unicode 8
|
||||
if (Tables9 == null) {
|
||||
initializeTable19();
|
||||
}
|
||||
return isJavaIdentifierPart0(codePoint, Tables9);
|
||||
} else if (complianceLevel <= ClassFileConstants.JDK11) {
|
||||
// java 11 supports Unicode 10
|
||||
if (Tables11 == null) {
|
||||
initializeTableJava11();
|
||||
}
|
||||
return isJavaIdentifierPart0(codePoint, Tables11);
|
||||
} else if (complianceLevel <= ClassFileConstants.JDK12) {
|
||||
// java 12 supports Unicode 11
|
||||
if (Tables12 == null) {
|
||||
initializeTableJava12();
|
||||
}
|
||||
return isJavaIdentifierPart0(codePoint, Tables12);
|
||||
} else if (complianceLevel <= ClassFileConstants.JDK14) {
|
||||
// java 13 and 14 support Unicode 12.1
|
||||
if (Tables13 == null) {
|
||||
initializeTableJava13();
|
||||
}
|
||||
return isJavaIdentifierPart0(codePoint, Tables13);
|
||||
|
||||
} else {
|
||||
// java 15 supports Unicode 13
|
||||
if (Tables15 == null) {
|
||||
initializeTableJava15();
|
||||
}
|
||||
return isJavaIdentifierPart0(codePoint, Tables15, true);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isJavaIdentifierStart(char c) {
|
||||
if (c < MAX_OBVIOUS) {
|
||||
return (ScannerHelper.OBVIOUS_IDENT_CHAR_NATURES[c] & ScannerHelper.C_IDENT_START) != 0;
|
||||
}
|
||||
return Character.isJavaIdentifierStart(c);
|
||||
}
|
||||
public static boolean isJavaIdentifierStart(long complianceLevel, char c) {
|
||||
if (c < MAX_OBVIOUS) {
|
||||
return (ScannerHelper.OBVIOUS_IDENT_CHAR_NATURES[c] & ScannerHelper.C_IDENT_START) != 0;
|
||||
}
|
||||
return ScannerHelper.isJavaIdentifierStart(complianceLevel, (int) c);
|
||||
}
|
||||
|
||||
private static boolean isJavaIdentifierStart0(int codePoint, long[][][] tables) {
|
||||
return isJavaIdentifierStart0(codePoint, tables, false);
|
||||
}
|
||||
private static boolean isJavaIdentifierStart0(int codePoint, long[][][] tables, boolean isJava15orAbove) {
|
||||
switch((codePoint & 0x1F0000) >> 16) {
|
||||
case 0 :
|
||||
return isBitSet(tables[START_INDEX][0], codePoint & 0xFFFF);
|
||||
case 1 :
|
||||
return isBitSet(tables[START_INDEX][1], codePoint & 0xFFFF);
|
||||
case 2 :
|
||||
return isBitSet(tables[START_INDEX][2], codePoint & 0xFFFF);
|
||||
case 3 :
|
||||
if (isJava15orAbove)
|
||||
return isBitSet(tables[START_INDEX][3], codePoint & 0xFFFF);
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public static boolean isJavaIdentifierStart(long complianceLevel, int codePoint) {
|
||||
if (complianceLevel <= ClassFileConstants.JDK1_6) {
|
||||
if (Tables == null) {
|
||||
initializeTable();
|
||||
}
|
||||
return isJavaIdentifierStart0(codePoint, Tables);
|
||||
} else if (complianceLevel <= ClassFileConstants.JDK1_7) {
|
||||
// java 7 supports Unicode 6
|
||||
if (Tables7 == null) {
|
||||
initializeTable17();
|
||||
}
|
||||
return isJavaIdentifierStart0(codePoint, Tables7);
|
||||
} else if (complianceLevel <= ClassFileConstants.JDK1_8) {
|
||||
// java 8 supports Unicode 6.2
|
||||
if (Tables8 == null) {
|
||||
initializeTable18();
|
||||
}
|
||||
return isJavaIdentifierStart0(codePoint, Tables8);
|
||||
} else if (complianceLevel <= ClassFileConstants.JDK10) {
|
||||
// java 9/10 supports Unicode 8
|
||||
if (Tables9 == null) {
|
||||
initializeTable19();
|
||||
}
|
||||
return isJavaIdentifierStart0(codePoint, Tables9);
|
||||
} else if (complianceLevel <= ClassFileConstants.JDK11) {
|
||||
// java 11 supports Unicode 10
|
||||
if (Tables11 == null) {
|
||||
initializeTableJava11();
|
||||
}
|
||||
return isJavaIdentifierStart0(codePoint, Tables11);
|
||||
} else if (complianceLevel <= ClassFileConstants.JDK12) {
|
||||
// java 12 supports Unicode 11
|
||||
if (Tables12 == null) {
|
||||
initializeTableJava12();
|
||||
}
|
||||
return isJavaIdentifierStart0(codePoint, Tables12);
|
||||
} else if (complianceLevel <= ClassFileConstants.JDK14) {
|
||||
// java 13 and 14 support Unicode 12.1
|
||||
if (Tables13 == null) {
|
||||
initializeTableJava13();
|
||||
}
|
||||
return isJavaIdentifierStart0(codePoint, Tables13);
|
||||
} else {
|
||||
// java 15 supports Unicode 13
|
||||
if (Tables15 == null) {
|
||||
initializeTableJava15();
|
||||
}
|
||||
return isJavaIdentifierStart0(codePoint, Tables15, true);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isDigit(char c) throws InvalidInputException {
|
||||
if(c < ScannerHelper.MAX_OBVIOUS) {
|
||||
return (ScannerHelper.OBVIOUS_IDENT_CHAR_NATURES[c] & ScannerHelper.C_DIGIT) != 0;
|
||||
}
|
||||
return Character.isDigit(c);
|
||||
}
|
||||
public static int digit(char c, int radix) {
|
||||
if (c < ScannerHelper.MAX_OBVIOUS) {
|
||||
switch(radix) {
|
||||
case 8 :
|
||||
if (c >= 48 && c <= 55) {
|
||||
return c - 48;
|
||||
}
|
||||
return -1;
|
||||
case 10 :
|
||||
if (c >= 48 && c <= 57) {
|
||||
return c - 48;
|
||||
}
|
||||
return -1;
|
||||
case 16 :
|
||||
if (c >= 48 && c <= 57) {
|
||||
return c - 48;
|
||||
}
|
||||
if (c >= 65 && c <= 70) {
|
||||
return c - 65 + 10;
|
||||
}
|
||||
if (c >= 97 && c <= 102) {
|
||||
return c - 97 + 10;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return Character.digit(c, radix);
|
||||
}
|
||||
public static int getNumericValue(char c) {
|
||||
if (c < ScannerHelper.MAX_OBVIOUS) {
|
||||
switch(ScannerHelper.OBVIOUS_IDENT_CHAR_NATURES[c]) {
|
||||
case C_DIGIT :
|
||||
return c - '0';
|
||||
case C_LOWER_LETTER :
|
||||
return 10 + c - 'a';
|
||||
case C_UPPER_LETTER :
|
||||
return 10 + c - 'A';
|
||||
}
|
||||
}
|
||||
return Character.getNumericValue(c);
|
||||
}
|
||||
public static int getHexadecimalValue(char c) {
|
||||
switch(c) {
|
||||
case '0' :
|
||||
return 0;
|
||||
case '1' :
|
||||
return 1;
|
||||
case '2' :
|
||||
return 2;
|
||||
case '3' :
|
||||
return 3;
|
||||
case '4' :
|
||||
return 4;
|
||||
case '5' :
|
||||
return 5;
|
||||
case '6' :
|
||||
return 6;
|
||||
case '7' :
|
||||
return 7;
|
||||
case '8' :
|
||||
return 8;
|
||||
case '9' :
|
||||
return 9;
|
||||
case 'A' :
|
||||
case 'a' :
|
||||
return 10;
|
||||
case 'B' :
|
||||
case 'b' :
|
||||
return 11;
|
||||
case 'C' :
|
||||
case 'c' :
|
||||
return 12;
|
||||
case 'D' :
|
||||
case 'd' :
|
||||
return 13;
|
||||
case 'E' :
|
||||
case 'e' :
|
||||
return 14;
|
||||
case 'F' :
|
||||
case 'f' :
|
||||
return 15;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
public static char toUpperCase(char c) {
|
||||
if (c < MAX_OBVIOUS) {
|
||||
if ((ScannerHelper.OBVIOUS_IDENT_CHAR_NATURES[c] & ScannerHelper.C_UPPER_LETTER) != 0) {
|
||||
return c;
|
||||
} else if ((ScannerHelper.OBVIOUS_IDENT_CHAR_NATURES[c] & ScannerHelper.C_LOWER_LETTER) != 0) {
|
||||
return (char) (c - 32);
|
||||
}
|
||||
}
|
||||
return Character.toUpperCase(c);
|
||||
}
|
||||
public static char toLowerCase(char c) {
|
||||
if (c < MAX_OBVIOUS) {
|
||||
if ((ScannerHelper.OBVIOUS_IDENT_CHAR_NATURES[c] & ScannerHelper.C_LOWER_LETTER) != 0) {
|
||||
return c;
|
||||
} else if ((ScannerHelper.OBVIOUS_IDENT_CHAR_NATURES[c] & ScannerHelper.C_UPPER_LETTER) != 0) {
|
||||
return (char) (32 + c);
|
||||
}
|
||||
}
|
||||
return Character.toLowerCase(c);
|
||||
}
|
||||
public static boolean isLowerCase(char c) {
|
||||
if (c < MAX_OBVIOUS) {
|
||||
return (ScannerHelper.OBVIOUS_IDENT_CHAR_NATURES[c] & ScannerHelper.C_LOWER_LETTER) != 0;
|
||||
}
|
||||
return Character.isLowerCase(c);
|
||||
}
|
||||
public static boolean isUpperCase(char c) {
|
||||
if (c < MAX_OBVIOUS) {
|
||||
return (ScannerHelper.OBVIOUS_IDENT_CHAR_NATURES[c] & ScannerHelper.C_UPPER_LETTER) != 0;
|
||||
}
|
||||
return Character.isUpperCase(c);
|
||||
}
|
||||
/**
|
||||
* Include also non JLS whitespaces.
|
||||
*
|
||||
* return true if Character.isWhitespace(c) would return true
|
||||
*/
|
||||
public static boolean isWhitespace(char c) {
|
||||
if (c < MAX_OBVIOUS) {
|
||||
return (ScannerHelper.OBVIOUS_IDENT_CHAR_NATURES[c] & ScannerHelper.C_SPACE) != 0;
|
||||
}
|
||||
return Character.isWhitespace(c);
|
||||
}
|
||||
public static boolean isLetter(char c) {
|
||||
if (c < MAX_OBVIOUS) {
|
||||
return (ScannerHelper.OBVIOUS_IDENT_CHAR_NATURES[c] & (ScannerHelper.C_UPPER_LETTER | ScannerHelper.C_LOWER_LETTER)) != 0;
|
||||
}
|
||||
return Character.isLetter(c);
|
||||
}
|
||||
public static boolean isLetterOrDigit(char c) {
|
||||
if (c < MAX_OBVIOUS) {
|
||||
return (ScannerHelper.OBVIOUS_IDENT_CHAR_NATURES[c] & (ScannerHelper.C_UPPER_LETTER | ScannerHelper.C_LOWER_LETTER | ScannerHelper.C_DIGIT)) != 0;
|
||||
}
|
||||
return Character.isLetterOrDigit(c);
|
||||
}
|
||||
|
||||
public static class InvalidInputException extends RuntimeException {}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,653 @@
|
||||
package org.eclipse.jdt.internal.compiler.util;
|
||||
|
||||
import org.eclipse.jdt.core.compiler.CharOperation;
|
||||
|
||||
public class Util {
|
||||
|
||||
/**
|
||||
* Character constant indicating the primitive type boolean in a signature.
|
||||
* Value is <code>'Z'</code>.
|
||||
*/
|
||||
public static final char C_BOOLEAN = 'Z';
|
||||
|
||||
/**
|
||||
* Character constant indicating the primitive type byte in a signature.
|
||||
* Value is <code>'B'</code>.
|
||||
*/
|
||||
public static final char C_BYTE = 'B';
|
||||
|
||||
/**
|
||||
* Character constant indicating the primitive type char in a signature.
|
||||
* Value is <code>'C'</code>.
|
||||
*/
|
||||
public static final char C_CHAR = 'C';
|
||||
|
||||
/**
|
||||
* Character constant indicating the primitive type double in a signature.
|
||||
* Value is <code>'D'</code>.
|
||||
*/
|
||||
public static final char C_DOUBLE = 'D';
|
||||
|
||||
/**
|
||||
* Character constant indicating the primitive type float in a signature.
|
||||
* Value is <code>'F'</code>.
|
||||
*/
|
||||
public static final char C_FLOAT = 'F';
|
||||
|
||||
/**
|
||||
* Character constant indicating the primitive type int in a signature.
|
||||
* Value is <code>'I'</code>.
|
||||
*/
|
||||
public static final char C_INT = 'I';
|
||||
|
||||
/**
|
||||
* Character constant indicating the semicolon in a signature.
|
||||
* Value is <code>';'</code>.
|
||||
*/
|
||||
public static final char C_SEMICOLON = ';';
|
||||
|
||||
/**
|
||||
* Character constant indicating the colon in a signature.
|
||||
* Value is <code>':'</code>.
|
||||
* @since 3.0
|
||||
*/
|
||||
public static final char C_COLON = ':';
|
||||
|
||||
/**
|
||||
* Character constant indicating the primitive type long in a signature.
|
||||
* Value is <code>'J'</code>.
|
||||
*/
|
||||
public static final char C_LONG = 'J';
|
||||
|
||||
/**
|
||||
* Character constant indicating the primitive type short in a signature.
|
||||
* Value is <code>'S'</code>.
|
||||
*/
|
||||
public static final char C_SHORT = 'S';
|
||||
|
||||
/**
|
||||
* Character constant indicating result type void in a signature.
|
||||
* Value is <code>'V'</code>.
|
||||
*/
|
||||
public static final char C_VOID = 'V';
|
||||
|
||||
/**
|
||||
* Character constant indicating the start of a resolved type variable in a
|
||||
* signature. Value is <code>'T'</code>.
|
||||
* @since 3.0
|
||||
*/
|
||||
public static final char C_TYPE_VARIABLE = 'T';
|
||||
|
||||
/**
|
||||
* Character constant indicating an unbound wildcard type argument
|
||||
* in a signature.
|
||||
* Value is <code>'*'</code>.
|
||||
* @since 3.0
|
||||
*/
|
||||
public static final char C_STAR = '*';
|
||||
|
||||
/**
|
||||
* Character constant indicating an exception in a signature.
|
||||
* Value is <code>'^'</code>.
|
||||
* @since 3.1
|
||||
*/
|
||||
public static final char C_EXCEPTION_START = '^';
|
||||
|
||||
/**
|
||||
* Character constant indicating a bound wildcard type argument
|
||||
* in a signature with extends clause.
|
||||
* Value is <code>'+'</code>.
|
||||
* @since 3.1
|
||||
*/
|
||||
public static final char C_EXTENDS = '+';
|
||||
|
||||
/**
|
||||
* Character constant indicating a bound wildcard type argument
|
||||
* in a signature with super clause.
|
||||
* Value is <code>'-'</code>.
|
||||
* @since 3.1
|
||||
*/
|
||||
public static final char C_SUPER = '-';
|
||||
|
||||
/**
|
||||
* Character constant indicating the dot in a signature.
|
||||
* Value is <code>'.'</code>.
|
||||
*/
|
||||
public static final char C_DOT = '.';
|
||||
|
||||
/**
|
||||
* Character constant indicating the dollar in a signature.
|
||||
* Value is <code>'$'</code>.
|
||||
*/
|
||||
public static final char C_DOLLAR = '$';
|
||||
|
||||
/**
|
||||
* Character constant indicating an array type in a signature.
|
||||
* Value is <code>'['</code>.
|
||||
*/
|
||||
public static final char C_ARRAY = '[';
|
||||
|
||||
/**
|
||||
* Character constant indicating the start of a resolved, named type in a
|
||||
* signature. Value is <code>'L'</code>.
|
||||
*/
|
||||
public static final char C_RESOLVED = 'L';
|
||||
|
||||
/**
|
||||
* Character constant indicating the start of an unresolved, named type in a
|
||||
* signature. Value is <code>'Q'</code>.
|
||||
*/
|
||||
public static final char C_UNRESOLVED = 'Q';
|
||||
|
||||
/**
|
||||
* Character constant indicating the end of a named type in a signature.
|
||||
* Value is <code>';'</code>.
|
||||
*/
|
||||
public static final char C_NAME_END = ';';
|
||||
|
||||
/**
|
||||
* Character constant indicating the start of a parameter type list in a
|
||||
* signature. Value is <code>'('</code>.
|
||||
*/
|
||||
public static final char C_PARAM_START = '(';
|
||||
|
||||
/**
|
||||
* Character constant indicating the end of a parameter type list in a
|
||||
* signature. Value is <code>')'</code>.
|
||||
*/
|
||||
public static final char C_PARAM_END = ')';
|
||||
|
||||
/**
|
||||
* Character constant indicating the start of a formal type parameter
|
||||
* (or type argument) list in a signature. Value is <code>'<'</code>.
|
||||
* @since 3.0
|
||||
*/
|
||||
public static final char C_GENERIC_START = '<';
|
||||
|
||||
/**
|
||||
* Character constant indicating the end of a generic type list in a
|
||||
* signature. Value is <code>'>'</code>.
|
||||
* @since 3.0
|
||||
*/
|
||||
public static final char C_GENERIC_END = '>';
|
||||
|
||||
/**
|
||||
* Character constant indicating a capture of a wildcard type in a
|
||||
* signature. Value is <code>'!'</code>.
|
||||
* @since 3.1
|
||||
*/
|
||||
public static final char C_CAPTURE = '!';
|
||||
|
||||
public static final String EMPTY_STRING = new String(CharOperation.NO_CHAR);
|
||||
|
||||
public static int getParameterCount(char[] methodSignature) {
|
||||
try {
|
||||
int count = 0;
|
||||
int i = CharOperation.indexOf(C_PARAM_START, methodSignature);
|
||||
if (i < 0) {
|
||||
throw new IllegalArgumentException(String.valueOf(methodSignature));
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
for (;;) {
|
||||
if (methodSignature[i] == C_PARAM_END) {
|
||||
return count;
|
||||
}
|
||||
int e= Util.scanTypeSignature(methodSignature, i);
|
||||
if (e < 0) {
|
||||
throw new IllegalArgumentException(String.valueOf(methodSignature));
|
||||
} else {
|
||||
i = e + 1;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
throw new IllegalArgumentException(String.valueOf(methodSignature), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans the given string for a type signature starting at the given index
|
||||
* and returns the index of the last character.
|
||||
* <pre>
|
||||
* TypeSignature:
|
||||
* | BaseTypeSignature
|
||||
* | ArrayTypeSignature
|
||||
* | ClassTypeSignature
|
||||
* | TypeVariableSignature
|
||||
* </pre>
|
||||
*
|
||||
* @param string the signature string
|
||||
* @param start the 0-based character index of the first character
|
||||
* @return the 0-based character index of the last character
|
||||
* @exception IllegalArgumentException if this is not a type signature
|
||||
*/
|
||||
public static int scanTypeSignature(char[] string, int start) {
|
||||
// need a minimum 1 char
|
||||
if (start >= string.length) {
|
||||
throw newIllegalArgumentException(string, start);
|
||||
}
|
||||
char c = string[start];
|
||||
switch (c) {
|
||||
case C_ARRAY :
|
||||
return scanArrayTypeSignature(string, start);
|
||||
case C_RESOLVED :
|
||||
case C_UNRESOLVED :
|
||||
return scanClassTypeSignature(string, start);
|
||||
case C_TYPE_VARIABLE :
|
||||
return scanTypeVariableSignature(string, start);
|
||||
case C_BOOLEAN :
|
||||
case C_BYTE :
|
||||
case C_CHAR :
|
||||
case C_DOUBLE :
|
||||
case C_FLOAT :
|
||||
case C_INT :
|
||||
case C_LONG :
|
||||
case C_SHORT :
|
||||
case C_VOID :
|
||||
return scanBaseTypeSignature(string, start);
|
||||
case C_CAPTURE :
|
||||
return scanCaptureTypeSignature(string, start);
|
||||
case C_EXTENDS:
|
||||
case C_SUPER:
|
||||
case C_STAR:
|
||||
return scanTypeBoundSignature(string, start);
|
||||
default :
|
||||
throw newIllegalArgumentException(string, start);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans the given string for a base type signature starting at the given index
|
||||
* and returns the index of the last character.
|
||||
* <pre>
|
||||
* BaseTypeSignature:
|
||||
* <b>B</b> | <b>C</b> | <b>D</b> | <b>F</b> | <b>I</b>
|
||||
* | <b>J</b> | <b>S</b> | <b>V</b> | <b>Z</b>
|
||||
* </pre>
|
||||
* Note that although the base type "V" is only allowed in method return types,
|
||||
* there is no syntactic ambiguity. This method will accept them anywhere
|
||||
* without complaint.
|
||||
*
|
||||
* @param string the signature string
|
||||
* @param start the 0-based character index of the first character
|
||||
* @return the 0-based character index of the last character
|
||||
* @exception IllegalArgumentException if this is not a base type signature
|
||||
*/
|
||||
public static int scanBaseTypeSignature(char[] string, int start) {
|
||||
// need a minimum 1 char
|
||||
if (start >= string.length) {
|
||||
throw newIllegalArgumentException(string, start);
|
||||
}
|
||||
char c = string[start];
|
||||
if ("BCDFIJSVZ".indexOf(c) >= 0) { //$NON-NLS-1$
|
||||
return start;
|
||||
} else {
|
||||
throw newIllegalArgumentException(string, start);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans the given string for an array type signature starting at the given
|
||||
* index and returns the index of the last character.
|
||||
* <pre>
|
||||
* ArrayTypeSignature:
|
||||
* <b>[</b> TypeSignature
|
||||
* </pre>
|
||||
*
|
||||
* @param string the signature string
|
||||
* @param start the 0-based character index of the first character
|
||||
* @return the 0-based character index of the last character
|
||||
* @exception IllegalArgumentException if this is not an array type signature
|
||||
*/
|
||||
public static int scanArrayTypeSignature(char[] string, int start) {
|
||||
int length = string.length;
|
||||
// need a minimum 2 char
|
||||
if (start >= length - 1) {
|
||||
throw newIllegalArgumentException(string, start);
|
||||
}
|
||||
char c = string[start];
|
||||
if (c != C_ARRAY) {
|
||||
throw newIllegalArgumentException(string, start);
|
||||
}
|
||||
|
||||
c = string[++start];
|
||||
while(c == C_ARRAY) {
|
||||
// need a minimum 2 char
|
||||
if (start >= length - 1) {
|
||||
throw newIllegalArgumentException(string, start);
|
||||
}
|
||||
c = string[++start];
|
||||
}
|
||||
return scanTypeSignature(string, start);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans the given string for a capture of a wildcard type signature starting at the given
|
||||
* index and returns the index of the last character.
|
||||
* <pre>
|
||||
* CaptureTypeSignature:
|
||||
* <b>!</b> TypeBoundSignature
|
||||
* </pre>
|
||||
*
|
||||
* @param string the signature string
|
||||
* @param start the 0-based character index of the first character
|
||||
* @return the 0-based character index of the last character
|
||||
* @exception IllegalArgumentException if this is not a capture type signature
|
||||
*/
|
||||
public static int scanCaptureTypeSignature(char[] string, int start) {
|
||||
// need a minimum 2 char
|
||||
if (start >= string.length - 1) {
|
||||
throw newIllegalArgumentException(string, start);
|
||||
}
|
||||
char c = string[start];
|
||||
if (c != C_CAPTURE) {
|
||||
throw newIllegalArgumentException(string, start);
|
||||
}
|
||||
return scanTypeBoundSignature(string, start + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans the given string for a type variable signature starting at the given
|
||||
* index and returns the index of the last character.
|
||||
* <pre>
|
||||
* TypeVariableSignature:
|
||||
* <b>T</b> Identifier <b>;</b>
|
||||
* </pre>
|
||||
*
|
||||
* @param string the signature string
|
||||
* @param start the 0-based character index of the first character
|
||||
* @return the 0-based character index of the last character
|
||||
* @exception IllegalArgumentException if this is not a type variable signature
|
||||
*/
|
||||
public static int scanTypeVariableSignature(char[] string, int start) {
|
||||
// need a minimum 3 chars "Tx;"
|
||||
if (start >= string.length - 2) {
|
||||
throw newIllegalArgumentException(string, start);
|
||||
}
|
||||
// must start in "T"
|
||||
char c = string[start];
|
||||
if (c != C_TYPE_VARIABLE) {
|
||||
throw newIllegalArgumentException(string, start);
|
||||
}
|
||||
int id = scanIdentifier(string, start + 1);
|
||||
c = string[id + 1];
|
||||
if (c == C_SEMICOLON) {
|
||||
return id + 1;
|
||||
} else {
|
||||
throw newIllegalArgumentException(string, start);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans the given string for an identifier starting at the given
|
||||
* index and returns the index of the last character.
|
||||
* Stop characters are: ";", ":", "<", ">", "/", ".".
|
||||
*
|
||||
* @param string the signature string
|
||||
* @param start the 0-based character index of the first character
|
||||
* @return the 0-based character index of the last character
|
||||
* @exception IllegalArgumentException if this is not an identifier
|
||||
*/
|
||||
public static int scanIdentifier(char[] string, int start) {
|
||||
// need a minimum 1 char
|
||||
if (start >= string.length) {
|
||||
throw newIllegalArgumentException(string, start);
|
||||
}
|
||||
int p = start;
|
||||
while (true) {
|
||||
char c = string[p];
|
||||
if (c == '<' || c == '>' || c == ':' || c == ';' || c == '.' || c == '/') {
|
||||
return p - 1;
|
||||
}
|
||||
p++;
|
||||
if (p == string.length) {
|
||||
return p - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans the given string for a class type signature starting at the given
|
||||
* index and returns the index of the last character.
|
||||
* <pre>
|
||||
* ClassTypeSignature:
|
||||
* { <b>L</b> | <b>Q</b> } Identifier
|
||||
* { { <b>/</b> | <b>.</b> Identifier [ <b><</b> TypeArgumentSignature* <b>></b> ] }
|
||||
* <b>;</b>
|
||||
* </pre>
|
||||
* Note that although all "/"-identifiers most come before "."-identifiers,
|
||||
* there is no syntactic ambiguity. This method will accept them without
|
||||
* complaint.
|
||||
*
|
||||
* @param string the signature string
|
||||
* @param start the 0-based character index of the first character
|
||||
* @return the 0-based character index of the last character
|
||||
* @exception IllegalArgumentException if this is not a class type signature
|
||||
*/
|
||||
public static int scanClassTypeSignature(char[] string, int start) {
|
||||
// need a minimum 3 chars "Lx;"
|
||||
if (start >= string.length - 2) {
|
||||
throw newIllegalArgumentException(string, start);
|
||||
}
|
||||
// must start in "L" or "Q"
|
||||
char c = string[start];
|
||||
if (c != C_RESOLVED && c != C_UNRESOLVED) {
|
||||
return -1;
|
||||
}
|
||||
int p = start + 1;
|
||||
while (true) {
|
||||
if (p >= string.length) {
|
||||
throw newIllegalArgumentException(string, start);
|
||||
}
|
||||
c = string[p];
|
||||
if (c == C_SEMICOLON) {
|
||||
// all done
|
||||
return p;
|
||||
} else if (c == C_GENERIC_START) {
|
||||
int e = scanTypeArgumentSignatures(string, p);
|
||||
p = e;
|
||||
} else if (c == C_DOT || c == '/') {
|
||||
int id = scanIdentifier(string, p + 1);
|
||||
p = id;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans the given string for a type bound signature starting at the given
|
||||
* index and returns the index of the last character.
|
||||
* <pre>
|
||||
* TypeBoundSignature:
|
||||
* <b>[-+]</b> TypeSignature <b>;</b>
|
||||
* <b>*</b></b>
|
||||
* </pre>
|
||||
*
|
||||
* @param string the signature string
|
||||
* @param start the 0-based character index of the first character
|
||||
* @return the 0-based character index of the last character
|
||||
* @exception IllegalArgumentException if this is not a type variable signature
|
||||
*/
|
||||
public static int scanTypeBoundSignature(char[] string, int start) {
|
||||
// need a minimum 1 char for wildcard
|
||||
if (start >= string.length) {
|
||||
throw newIllegalArgumentException(string, start);
|
||||
}
|
||||
char c = string[start];
|
||||
switch (c) {
|
||||
case C_STAR :
|
||||
return start;
|
||||
case C_SUPER :
|
||||
case C_EXTENDS :
|
||||
break;
|
||||
default :
|
||||
// must start in "+/-"
|
||||
throw newIllegalArgumentException(string, start);
|
||||
}
|
||||
c = string[++start];
|
||||
if (c != C_STAR && start >= string.length -1) { // unless "-*" we need at least one more char, e.g. after "+[", other variants are even longer
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
switch (c) {
|
||||
case C_CAPTURE :
|
||||
return scanCaptureTypeSignature(string, start);
|
||||
case C_SUPER :
|
||||
case C_EXTENDS :
|
||||
return scanTypeBoundSignature(string, start);
|
||||
case C_RESOLVED :
|
||||
case C_UNRESOLVED :
|
||||
return scanClassTypeSignature(string, start);
|
||||
case C_TYPE_VARIABLE :
|
||||
return scanTypeVariableSignature(string, start);
|
||||
case C_ARRAY :
|
||||
return scanArrayTypeSignature(string, start);
|
||||
case C_STAR:
|
||||
return start;
|
||||
default:
|
||||
throw newIllegalArgumentException(string, start);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans the given string for a list of type argument signatures starting at
|
||||
* the given index and returns the index of the last character.
|
||||
* <pre>
|
||||
* TypeArgumentSignatures:
|
||||
* <b><</b> TypeArgumentSignature* <b>></b>
|
||||
* </pre>
|
||||
* Note that although there is supposed to be at least one type argument, there
|
||||
* is no syntactic ambiguity if there are none. This method will accept zero
|
||||
* type argument signatures without complaint.
|
||||
*
|
||||
* @param string the signature string
|
||||
* @param start the 0-based character index of the first character
|
||||
* @return the 0-based character index of the last character
|
||||
* @exception IllegalArgumentException if this is not a list of type arguments
|
||||
* signatures
|
||||
*/
|
||||
public static int scanTypeArgumentSignatures(char[] string, int start) {
|
||||
// need a minimum 2 char "<>"
|
||||
if (start >= string.length - 1) {
|
||||
throw newIllegalArgumentException(string, start);
|
||||
}
|
||||
char c = string[start];
|
||||
if (c != C_GENERIC_START) {
|
||||
throw newIllegalArgumentException(string, start);
|
||||
}
|
||||
int p = start + 1;
|
||||
while (true) {
|
||||
if (p >= string.length) {
|
||||
throw newIllegalArgumentException(string, start);
|
||||
}
|
||||
c = string[p];
|
||||
if (c == C_GENERIC_END) {
|
||||
return p;
|
||||
}
|
||||
int e = scanTypeArgumentSignature(string, p);
|
||||
p = e + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans the given string for a type argument signature starting at the given
|
||||
* index and returns the index of the last character.
|
||||
* <pre>
|
||||
* TypeArgumentSignature:
|
||||
* <b>*</b>
|
||||
* | <b>+</b> TypeSignature
|
||||
* | <b>-</b> TypeSignature
|
||||
* | TypeSignature
|
||||
* </pre>
|
||||
* Note that although base types are not allowed in type arguments, there is
|
||||
* no syntactic ambiguity. This method will accept them without complaint.
|
||||
*
|
||||
* @param string the signature string
|
||||
* @param start the 0-based character index of the first character
|
||||
* @return the 0-based character index of the last character
|
||||
* @exception IllegalArgumentException if this is not a type argument signature
|
||||
*/
|
||||
public static int scanTypeArgumentSignature(char[] string, int start) {
|
||||
// need a minimum 1 char
|
||||
if (start >= string.length) {
|
||||
throw newIllegalArgumentException(string, start);
|
||||
}
|
||||
char c = string[start];
|
||||
switch (c) {
|
||||
case C_STAR :
|
||||
return start;
|
||||
case C_EXTENDS :
|
||||
case C_SUPER :
|
||||
return scanTypeBoundSignature(string, start);
|
||||
default :
|
||||
return scanTypeSignature(string, start);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean effectivelyEqual(Object [] one, Object [] two) {
|
||||
if (one == two)
|
||||
return true;
|
||||
int oneLength = one == null ? 0 : one.length;
|
||||
int twoLength = two == null ? 0 : two.length;
|
||||
if (oneLength != twoLength)
|
||||
return false;
|
||||
if (oneLength == 0)
|
||||
return true;
|
||||
for (int i = 0; i < one.length; i++) {
|
||||
if (one[i] != two[i])
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void appendEscapedChar(StringBuffer buffer, char c, boolean stringLiteral) {
|
||||
switch (c) {
|
||||
case '\b' :
|
||||
buffer.append("\\b"); //$NON-NLS-1$
|
||||
break;
|
||||
case '\t' :
|
||||
buffer.append("\\t"); //$NON-NLS-1$
|
||||
break;
|
||||
case '\n' :
|
||||
buffer.append("\\n"); //$NON-NLS-1$
|
||||
break;
|
||||
case '\f' :
|
||||
buffer.append("\\f"); //$NON-NLS-1$
|
||||
break;
|
||||
case '\r' :
|
||||
buffer.append("\\r"); //$NON-NLS-1$
|
||||
break;
|
||||
case '\"':
|
||||
if (stringLiteral) {
|
||||
buffer.append("\\\""); //$NON-NLS-1$
|
||||
} else {
|
||||
buffer.append(c);
|
||||
}
|
||||
break;
|
||||
case '\'':
|
||||
if (stringLiteral) {
|
||||
buffer.append(c);
|
||||
} else {
|
||||
buffer.append("\\\'"); //$NON-NLS-1$
|
||||
}
|
||||
break;
|
||||
case '\\':
|
||||
buffer.append("\\\\"); //$NON-NLS-1$
|
||||
break;
|
||||
default:
|
||||
if (c >= 0x20) {
|
||||
buffer.append(c);
|
||||
} else if (c >= 0x10) {
|
||||
buffer.append("\\u00").append(Integer.toHexString(c)); //$NON-NLS-1$
|
||||
} else if (c >= 0) {
|
||||
buffer.append("\\u000").append(Integer.toHexString(c)); //$NON-NLS-1$
|
||||
} else {
|
||||
buffer.append(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static IllegalArgumentException newIllegalArgumentException(char[] string, int start) {
|
||||
return new IllegalArgumentException("\"" + String.valueOf(string) + "\" at " + start); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
}
|
||||
}
|
||||
@@ -130,6 +130,7 @@ dependencies {
|
||||
implementation 'com.google.firebase:firebase-messaging'
|
||||
|
||||
// Local projects
|
||||
implementation project(':api-info')
|
||||
implementation project(':treeview')
|
||||
implementation project(':lsp')
|
||||
implementation project(':emulator')
|
||||
|
||||
@@ -705,28 +705,7 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
|
||||
|
||||
invalidateOptionsMenu();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGetDependencies(List<String> dependencies) {
|
||||
setStatus(getString(R.string.msg_starting_completion));
|
||||
mProject.setClassPaths(dependencies);
|
||||
createServices();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGetDependenciesFailed() {
|
||||
final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this, R.style.AppTheme_MaterialAlertDialog);
|
||||
builder.setNegativeButton(android.R.string.no, null)
|
||||
.setPositiveButton(android.R.string.yes, (p1, p2) -> {
|
||||
p1.dismiss();
|
||||
if(getBuildService() != null)
|
||||
getBuildService().initProject();
|
||||
})
|
||||
.setTitle(R.string.failed)
|
||||
.setMessage(R.string.msg_first_prepare_failed)
|
||||
.create().show();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onProjectLoaded(IDEProject project, Optional<IDEModule> appModule) {
|
||||
project.iconPath = mProject.getIconPath();
|
||||
@@ -751,8 +730,8 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyBuildModified() {
|
||||
|
||||
public void onBuildModified() {
|
||||
// Does nothing currently
|
||||
}
|
||||
|
||||
private boolean isClasspathValid(String path) {
|
||||
|
||||
@@ -7,7 +7,9 @@ import android.view.View;
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.itsaky.androidide.app.StudioActivity;
|
||||
import com.itsaky.androidide.databinding.ActivitySplashBinding;
|
||||
import com.itsaky.androidide.models.ConstantsBridge;
|
||||
import com.itsaky.androidide.models.ConstantsBridge;
|
||||
import android.text.TextUtils;
|
||||
import org.eclipse.jdt.core.Signature;
|
||||
|
||||
public class SplashActivity extends StudioActivity
|
||||
{
|
||||
|
||||
@@ -6,18 +6,39 @@ import android.util.TypedValue;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.itsaky.androidide.R;
|
||||
import com.itsaky.androidide.app.StudioApp;
|
||||
import com.itsaky.androidide.databinding.LayoutCompletionItemBinding;
|
||||
import com.itsaky.androidide.models.CompletionItemWrapper;
|
||||
import com.itsaky.androidide.models.CompletionListItem;
|
||||
import com.itsaky.androidide.models.SuggestItem;
|
||||
import com.itsaky.androidide.services.IDEService;
|
||||
import com.itsaky.androidide.utils.Either;
|
||||
import com.itsaky.androidide.utils.TypefaceUtils;
|
||||
import com.itsaky.apiinfo.ApiInfo;
|
||||
import com.itsaky.apiinfo.models.ClassInfo;
|
||||
import com.itsaky.apiinfo.models.MethodInfo;
|
||||
import com.itsaky.lsp.CompletionItemKind;
|
||||
import io.github.rosemoe.editor.struct.CompletionItem;
|
||||
import io.github.rosemoe.editor.widget.EditorCompletionAdapter;
|
||||
import java.util.Locale;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.itsaky.apiinfo.models.FieldInfo;
|
||||
import com.blankj.utilcode.util.ThreadUtils;
|
||||
import com.itsaky.androidide.utils.Logger;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.itsaky.apiinfo.models.Info;
|
||||
import android.text.TextUtils;
|
||||
|
||||
public class CompletionListAdapter extends EditorCompletionAdapter {
|
||||
|
||||
private static final Logger LOG = Logger.instance("CompletionListAdapter");
|
||||
|
||||
@Override
|
||||
public int getItemHeight() {
|
||||
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 40, Resources.getSystem().getDisplayMetrics());
|
||||
@@ -43,19 +64,139 @@ public class CompletionListAdapter extends EditorCompletionAdapter {
|
||||
type = item.getItemType().contains(".") ? item.getItemType().substring(item.getItemType().lastIndexOf(".") + 1) : item.getItemType();
|
||||
desc = item.getType() != CompletionListItem.Type.NOT_IMPORTED_CLASS ? item.getDetail() : getContext().getString(R.string.label_not_imported, item.getDetail());
|
||||
}
|
||||
|
||||
|
||||
binding.completionIconText.setText(header);
|
||||
binding.completionLabel.setText(label);
|
||||
binding.completionType.setText(type);
|
||||
binding.completionDetail.setText(desc);
|
||||
binding.completionIconText.setTypeface(TypefaceUtils.jetbrainsMono(), Typeface.BOLD);
|
||||
if(desc == null || desc.isEmpty())
|
||||
if (desc == null || desc.isEmpty())
|
||||
binding.completionDetail.setVisibility(View.GONE);
|
||||
|
||||
if (isCurrentCursorPosition)
|
||||
binding.getRoot().setBackgroundColor(ContextCompat.getColor(getContext(), R.color.completionList_backgroundSelected));
|
||||
else binding.getRoot().setBackgroundColor(ContextCompat.getColor(getContext(), R.color.completionList_background));
|
||||
|
||||
binding.completionApiInfo.setVisibility(View.GONE);
|
||||
|
||||
if (e != null && e.isLeft() && e.getLeft() instanceof CompletionItemWrapper) {
|
||||
showApiInfoIfNeeded((CompletionItemWrapper) e.getLeft(), binding.completionApiInfo);
|
||||
}
|
||||
|
||||
binding.getRoot().getViewTreeObserver().addOnGlobalLayoutListener(() -> {
|
||||
|
||||
ViewGroup.LayoutParams p = binding.completionIconText.getLayoutParams();
|
||||
p.height = binding.getRoot().getHeight();
|
||||
binding.completionIconText.setLayoutParams(p);
|
||||
});
|
||||
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
private void showApiInfoIfNeeded(final CompletionItemWrapper item, final TextView completionApiInfo) {
|
||||
|
||||
new Thread(() -> {
|
||||
final ApiInfo info = StudioApp.getInstance().getApiInfo();
|
||||
boolean hasRead = info != null && info.hasRead();
|
||||
boolean isValid = isValidForApiVersion(item.getItem());
|
||||
|
||||
if (hasRead && isValid) {
|
||||
|
||||
JsonElement element = item.getItem().data;
|
||||
if (element == null || !element.isJsonObject()) return;
|
||||
JsonObject data = element.getAsJsonObject();
|
||||
if (!data.has("className")) return;
|
||||
|
||||
final String className = data.get("className").getAsString();
|
||||
int kind = item.getItem().kind;
|
||||
|
||||
ClassInfo clazz = info.getClassByName(className);
|
||||
if(clazz == null) return;
|
||||
|
||||
Info apiInfo = clazz;
|
||||
|
||||
/**
|
||||
* If this Info is not a class info, find the right member
|
||||
*/
|
||||
if (kind == CompletionItemKind.Method
|
||||
&& data.has("erasedParameterTypes")
|
||||
&& data.has("memberName")) {
|
||||
JsonElement erasedParameterTypesElement = data.get("erasedParameterTypes");
|
||||
if(erasedParameterTypesElement.isJsonArray()) {
|
||||
String simpleName = data.get("memberName").getAsString();
|
||||
JsonArray erasedParameterTypes = erasedParameterTypesElement.getAsJsonArray();
|
||||
String[] paramTypes = new String[erasedParameterTypes.size()];
|
||||
for(int i=0;i<erasedParameterTypes.size();i++) {
|
||||
paramTypes[i] = erasedParameterTypes.get(i).getAsString();
|
||||
}
|
||||
|
||||
MethodInfo method = clazz.getMethod(simpleName, paramTypes);
|
||||
|
||||
if(method != null) {
|
||||
apiInfo = method;
|
||||
}
|
||||
}
|
||||
} else if(kind == CompletionItemKind.Field
|
||||
&& data.has("memberName")) {
|
||||
String simpleName = data.get("memberName").getAsString();
|
||||
FieldInfo field = clazz.getFieldByName(simpleName);
|
||||
|
||||
if(field != null) {
|
||||
apiInfo = field;
|
||||
}
|
||||
}
|
||||
|
||||
final StringBuilder infoBuilder = new StringBuilder();
|
||||
if (apiInfo != null && apiInfo.since > 1) {
|
||||
infoBuilder.append(completionApiInfo.getContext().getString(R.string.msg_api_info_since, apiInfo.since));
|
||||
}
|
||||
|
||||
if (apiInfo != null && apiInfo.removed > 0) {
|
||||
infoBuilder.append(completionApiInfo.getContext().getString(R.string.msg_api_info_removed, apiInfo.removed));
|
||||
}
|
||||
|
||||
if (apiInfo != null && apiInfo.deprecated > 0) {
|
||||
infoBuilder.append(completionApiInfo.getContext().getString(R.string.msg_api_info_deprecated, apiInfo.deprecated));
|
||||
}
|
||||
|
||||
ThreadUtils.runOnUiThread(() -> {
|
||||
if(infoBuilder.toString().trim().length() > 0) {
|
||||
completionApiInfo.setText(infoBuilder.toString().trim());
|
||||
completionApiInfo.setVisibility(View.VISIBLE);
|
||||
} else completionApiInfo.setVisibility(View.GONE);
|
||||
});
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
private boolean isValidForApiVersion(com.itsaky.lsp.CompletionItem item) {
|
||||
if (item == null) return false;
|
||||
final int type = item.kind;
|
||||
JsonElement element = item.data;
|
||||
if (
|
||||
|
||||
/**
|
||||
* These represent a class type
|
||||
*/
|
||||
(type == CompletionItemKind.Class
|
||||
|| type == CompletionItemKind.Interface
|
||||
|| type == CompletionItemKind.Enum
|
||||
|
||||
/**
|
||||
* These represent a method type
|
||||
*/
|
||||
|| type == CompletionItemKind.Method
|
||||
|| type == CompletionItemKind.Constructor
|
||||
|
||||
/**
|
||||
* A field type
|
||||
*/
|
||||
|| type == CompletionItemKind.Field)
|
||||
|
||||
&& element != null && element.isJsonObject()) {
|
||||
JsonObject data = element.getAsJsonObject();
|
||||
return data.has("className");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ import java.util.Locale;
|
||||
import com.blankj.utilcode.util.FileUtils;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
import com.itsaky.apiinfo.ApiInfo;
|
||||
|
||||
public class StudioApp extends MultiDexApplication
|
||||
{
|
||||
@@ -56,6 +57,8 @@ public class StudioApp extends MultiDexApplication
|
||||
private boolean stopGradleDaemon = true;
|
||||
private String sArch = "";
|
||||
|
||||
private ApiInfo mApiInfo;
|
||||
|
||||
private List<LanguageServerListener> serveralisteners = new ArrayList<>();
|
||||
|
||||
public static final boolean DEBUG = com.itsaky.androidide.BuildConfig.DEBUG;
|
||||
@@ -81,7 +84,6 @@ public class StudioApp extends MultiDexApplication
|
||||
this.instance = this;
|
||||
this.uncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
|
||||
Thread.setDefaultUncaughtExceptionHandler((thread, ex) -> handleCrash(thread, ex));
|
||||
initLogger();
|
||||
super.onCreate();
|
||||
mPrefsManager = new PreferenceManager(this);
|
||||
mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
|
||||
@@ -143,10 +145,23 @@ public class StudioApp extends MultiDexApplication
|
||||
private String getDevNotificationChannelName() {
|
||||
return getString(R.string.cms_channel_id_devs);
|
||||
}
|
||||
|
||||
private void initLogger() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads API version information from api-versions.xml
|
||||
*/
|
||||
public void initializeApiInformation() {
|
||||
if(mApiInfo == null || !mApiInfo.hasRead()) {
|
||||
File apiVersions = new File(Environment.BOOTCLASSPATH.getParentFile(), "data/api-versions.xml");
|
||||
if(apiVersions.exists() && apiVersions.isFile()) {
|
||||
mApiInfo = new ApiInfo(apiVersions);
|
||||
try {
|
||||
mApiInfo.readAsync(null);
|
||||
} catch (Exception e) {
|
||||
LOG.error("Failed to read API version information", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void stopAllDaemons() {
|
||||
newShell(null).bgAppend("gradle --stop");
|
||||
@@ -177,6 +192,10 @@ public class StudioApp extends MultiDexApplication
|
||||
public XMLCompletionService getXmlCompletionService() {
|
||||
return mXmlCompletionService;
|
||||
}
|
||||
|
||||
public ApiInfo getApiInfo() {
|
||||
return mApiInfo;
|
||||
}
|
||||
|
||||
public boolean areCompletorsStarted() {
|
||||
return mXmlCompletionService != null
|
||||
|
||||
@@ -106,7 +106,6 @@ public class CompletionItemWrapper implements SuggestItem, Comparable {
|
||||
|
||||
CharPosition startPos = content.getIndexer().getCharPosition(start);
|
||||
CharPosition endPos = content.getIndexer().getCharPosition(end);
|
||||
Logger.instance("CompletionItemWrapper").debug("PartialIdentifer Range: " + start + "," + end + ", text: " + content.subSequence(start, end));
|
||||
return new Range(new Position(startPos.line, startPos.column), new Position(endPos.line, endPos.column));
|
||||
}
|
||||
|
||||
@@ -130,9 +129,7 @@ public class CompletionItemWrapper implements SuggestItem, Comparable {
|
||||
return 1;
|
||||
}
|
||||
|
||||
private int getInsertLength() {
|
||||
if (prefix.endsWith(".")) return 0;
|
||||
else if (prefix.contains(".")) return prefix.substring(prefix.lastIndexOf(".") + 1).length();
|
||||
else return prefix.length();
|
||||
public CompletionItem getItem() {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,11 +127,7 @@ public class IDEService implements ShellServer.Callback {
|
||||
isBuilding = false;
|
||||
if(recreateShellOnDone)
|
||||
createShell();
|
||||
if(currentTask != null) {
|
||||
if(currentTask.getTaskID() == TASK_SHOW_DEPENDENCIES)
|
||||
listener.onGetDependenciesFailed();
|
||||
else listener.onBuildFailed(currentTask, line.trim());
|
||||
}
|
||||
listener.onBuildFailed(currentTask, line.trim());
|
||||
appendOutputSeparator();
|
||||
|
||||
execTask(BaseGradleTasks.TASKS);
|
||||
@@ -211,6 +207,10 @@ public class IDEService implements ShellServer.Callback {
|
||||
|
||||
server.didChangeWatchedFiles(new DidChangeWatchedFilesParams(createSourceChangeEvents()));
|
||||
server.buildModified();
|
||||
|
||||
if(listener != null) {
|
||||
listener.onBuildModified();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -295,6 +295,17 @@ public class IDEService implements ShellServer.Callback {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return An int[] containing minimumSdk at index 0 and targetSdk at index 1 or {1, 1}
|
||||
*/
|
||||
public int[] getSdkInfo() {
|
||||
if(mAppModule != null) {
|
||||
return new int[]{mAppModule.minSdk.apiLevel, mAppModule.targetSdk.apiLevel};
|
||||
}
|
||||
|
||||
return new int[]{1, 1};
|
||||
}
|
||||
|
||||
public void initProject() {
|
||||
execTask(BaseGradleTasks.INITIALIZE_IDE_PROJECT);
|
||||
}
|
||||
@@ -379,20 +390,71 @@ public class IDEService implements ShellServer.Callback {
|
||||
public boolean isBuilding() {
|
||||
return isBuilding;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A client should implement this interface to get callbacks about a build
|
||||
*/
|
||||
public static interface BuildListener {
|
||||
void notifyBuildModified();
|
||||
void onProjectLoaded(IDEProject project, Optional<IDEModule> appModule);
|
||||
void onGetDependencies(List<String> dependencies);
|
||||
void onGetDependenciesFailed();
|
||||
/**
|
||||
* Called to notify the client about the modification of build/generated files
|
||||
*/
|
||||
void onBuildModified();
|
||||
|
||||
/**
|
||||
* Called when the project has been loaded and its data has been read
|
||||
*
|
||||
* @param project The loaded project
|
||||
* @param appModule The main application module
|
||||
*/
|
||||
void onProjectLoaded(IDEProject project, Optional<IDEModule> appModule);
|
||||
|
||||
/**
|
||||
* Called when a Gradle Daemon is being started
|
||||
*
|
||||
* @param task Task that is currently running
|
||||
*/
|
||||
void onStartingGradleDaemon(GradleTask task);
|
||||
|
||||
/**
|
||||
* Called when a task is started
|
||||
*
|
||||
* @param task Task that is currently running
|
||||
* @param name Name of this task that should be shown to user
|
||||
*/
|
||||
void onRunTask(GradleTask task, String name);
|
||||
|
||||
/**
|
||||
* Notifys about a successful build
|
||||
*
|
||||
* @param task Task that succeeded
|
||||
* @param msg Successful message
|
||||
*/
|
||||
void onBuildSuccessful(GradleTask task, String msg);
|
||||
|
||||
/**
|
||||
* Notifys about a failed build
|
||||
*
|
||||
* @param task Task that failed
|
||||
* @param msg Failure message
|
||||
*/
|
||||
void onBuildFailed(GradleTask task, String msg);
|
||||
|
||||
/**
|
||||
* Called to notify client to save any opened files
|
||||
*/
|
||||
void saveFiles();
|
||||
|
||||
/**
|
||||
* Notifys the client to append the build output that should be shown to user
|
||||
*
|
||||
* @param task Task that is currently running
|
||||
* @param text Output to append
|
||||
*/
|
||||
void appendOutput(GradleTask task, CharSequence text);
|
||||
|
||||
/**
|
||||
* Called to notify the client to prepare for a build
|
||||
*/
|
||||
void prepare();
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,11 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import android.os.Build;
|
||||
import com.itsaky.apiinfo.ApiInfo;
|
||||
import com.itsaky.apiinfo.models.ClassInfo;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.itsaky.apiinfo.models.MethodInfo;
|
||||
|
||||
public final class Environment {
|
||||
|
||||
@@ -105,6 +110,8 @@ public final class Environment {
|
||||
|
||||
public static void setBootClasspath(File file) {
|
||||
BOOTCLASSPATH = new File(file.getAbsolutePath());
|
||||
|
||||
StudioApp.getInstance().initializeApiInformation();
|
||||
}
|
||||
|
||||
public static Map<String, String> getEnvironment(boolean publicUse) {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
tools:ignore="SmallSp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:background="@color/primaryLightColor">
|
||||
|
||||
@@ -47,12 +47,26 @@
|
||||
android:ellipsize="end"
|
||||
android:singleLine="true"
|
||||
android:layout_toEndOf="@id/completion_iconText"
|
||||
android:layout_marginBottom="2dp"
|
||||
android:layout_marginEnd="4dp"/>
|
||||
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/completion_detail"
|
||||
android:id="@+id/completion_api_info"
|
||||
android:textColor="@color/primaryTextColor"
|
||||
android:textSize="11sp"
|
||||
android:gravity="center_vertical"
|
||||
android:ellipsize="end"
|
||||
android:singleLine="true"
|
||||
android:layout_toEndOf="@id/completion_iconText"
|
||||
android:layout_marginBottom="2dp"
|
||||
android:layout_marginEnd="4dp"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="30dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:id="@+id/completion_iconText"
|
||||
android:background="@color/secondaryColor"
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<string name="msg_api_info_since">Since API %d\n</string>
|
||||
<string name="msg_api_info_removed">Removed in API %d\n</string>
|
||||
<string name="msg_api_info_deprecated">Deprecated in API %d\n</string>
|
||||
<string name="title_confirm_open_project">Open last project?</string>
|
||||
<string name="msg_confirm_open_project">Do you want me to open last opened project? Opened project was:\n%s</string>
|
||||
<string name="title_open_projects">Open last project</string>
|
||||
|
||||
@@ -4,5 +4,6 @@ include ':lsp'
|
||||
include ':emulatorview'
|
||||
include ':emulator'
|
||||
include ':javapoet'
|
||||
include ':api-info'
|
||||
|
||||
rootProject.name = "Android IDE"
|
||||
|
||||
Reference in New Issue
Block a user