mirror of
https://github.com/adelphes/android-dev-ext.git
synced 2025-12-23 09:59:25 +00:00
set configurable trace logging and update section names
This commit is contained in:
@@ -18,6 +18,7 @@ const { Label, Local, MethodDeclarations, ResolvedIdent, ResolveInfo } = require
|
|||||||
const { resolveImports, resolveSingleImport } = require('../java/import-resolver');
|
const { resolveImports, resolveSingleImport } = require('../java/import-resolver');
|
||||||
const { checkAssignment, getTypeInheritanceList } = require('./expression-resolver');
|
const { checkAssignment, getTypeInheritanceList } = require('./expression-resolver');
|
||||||
const { checkStatementBlock } = require('./statement-validater');
|
const { checkStatementBlock } = require('./statement-validater');
|
||||||
|
const { time, timeEnd } = require('../logging');
|
||||||
|
|
||||||
const { ArrayIndexExpression } = require("./expressiontypes/ArrayIndexExpression");
|
const { ArrayIndexExpression } = require("./expressiontypes/ArrayIndexExpression");
|
||||||
const { ArrayValueExpression } = require("./expressiontypes/ArrayValueExpression");
|
const { ArrayValueExpression } = require("./expressiontypes/ArrayValueExpression");
|
||||||
@@ -199,10 +200,6 @@ function extractSourceTypes(tokens, typemap) {
|
|||||||
*/
|
*/
|
||||||
function parse(docs, cached_units, typemap) {
|
function parse(docs, cached_units, typemap) {
|
||||||
|
|
||||||
const timers = new Set();
|
|
||||||
const time = name => (timers.add(name), console.time(name));
|
|
||||||
const timeEnd = name => (timers.delete(name), console.timeEnd(name));
|
|
||||||
|
|
||||||
time('tokenize');
|
time('tokenize');
|
||||||
const sources = docs.reduce((arr, doc) => {
|
const sources = docs.reduce((arr, doc) => {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -31,8 +31,6 @@ function parseMethodBodies(unit, typemap) {
|
|||||||
* @returns {import('./parsetypes/parse-problem')[]}
|
* @returns {import('./parsetypes/parse-problem')[]}
|
||||||
*/
|
*/
|
||||||
function validate(unit, androidLibrary) {
|
function validate(unit, androidLibrary) {
|
||||||
console.time('validation');
|
|
||||||
|
|
||||||
let probs = [];
|
let probs = [];
|
||||||
|
|
||||||
const module_validaters = [
|
const module_validaters = [
|
||||||
@@ -54,7 +52,6 @@ function validate(unit, androidLibrary) {
|
|||||||
module_validaters.map(v => v(unit.types, unit)),
|
module_validaters.map(v => v(unit.types, unit)),
|
||||||
...probs,
|
...probs,
|
||||||
];
|
];
|
||||||
console.timeEnd('validation');
|
|
||||||
|
|
||||||
function flatten(arr) {
|
function flatten(arr) {
|
||||||
let res = arr;
|
let res = arr;
|
||||||
|
|||||||
43
langserver/logging.js
Normal file
43
langserver/logging.js
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
const { Settings } = require('./settings');
|
||||||
|
|
||||||
|
const earlyTraceBuffer = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} s
|
||||||
|
*/
|
||||||
|
function trace(s) {
|
||||||
|
if (Settings.updateCount > 0 && !Settings.trace) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const msg = `${Date.now()}: ${s}`;
|
||||||
|
// before we've retrieved the trace setting, buffer the messages
|
||||||
|
if (Settings.updateCount === 0) {
|
||||||
|
earlyTraceBuffer.push(msg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (earlyTraceBuffer.length) {
|
||||||
|
earlyTraceBuffer.splice(0, earlyTraceBuffer.length).forEach(msg => console.log(msg));
|
||||||
|
}
|
||||||
|
console.log(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
function info(msg) {
|
||||||
|
console.log(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
function time(label) {
|
||||||
|
if (Settings.trace) {
|
||||||
|
console.time(label);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function timeEnd(label) {
|
||||||
|
if (Settings.trace) {
|
||||||
|
console.timeEnd(label);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.info = info;
|
||||||
|
exports.trace = trace;
|
||||||
|
exports.time = time;
|
||||||
|
exports.timeEnd = timeEnd;
|
||||||
@@ -4,30 +4,26 @@ const os = require('os');
|
|||||||
const {
|
const {
|
||||||
createConnection,
|
createConnection,
|
||||||
TextDocuments,
|
TextDocuments,
|
||||||
//TextDocument,
|
|
||||||
Diagnostic,
|
Diagnostic,
|
||||||
DiagnosticSeverity,
|
|
||||||
ProposedFeatures,
|
ProposedFeatures,
|
||||||
//InitializeParams,
|
|
||||||
DidChangeConfigurationNotification,
|
DidChangeConfigurationNotification,
|
||||||
CompletionItem,
|
CompletionItem,
|
||||||
CompletionItemKind,
|
CompletionItemKind,
|
||||||
TextDocumentSyncKind,
|
TextDocumentSyncKind,
|
||||||
Position,
|
|
||||||
//TextDocumentPositionParams
|
|
||||||
} = require('vscode-languageserver');
|
} = require('vscode-languageserver');
|
||||||
|
|
||||||
const { TextDocument } = require('vscode-languageserver-textdocument');
|
const { TextDocument } = require('vscode-languageserver-textdocument');
|
||||||
|
|
||||||
const { Settings } = require('./settings');
|
|
||||||
const { loadAndroidSystemLibrary } = require('./java/java-libraries');
|
const { loadAndroidSystemLibrary } = require('./java/java-libraries');
|
||||||
const { JavaType, CEIType, ArrayType, PrimitiveType, Method } = require('java-mti');
|
const { JavaType, CEIType, ArrayType, PrimitiveType, Method } = require('java-mti');
|
||||||
|
|
||||||
const { ParseProblem } = require('./java/parser');
|
const { ParseProblem } = require('./java/parser');
|
||||||
const { parse } = require('./java/body-parser3');
|
const { parse } = require('./java/body-parser3');
|
||||||
const { SourceUnit } = require('./java/source-types');
|
const { SourceUnit } = require('./java/source-types');
|
||||||
const { validate, parseMethodBodies } = require('./java/validater');
|
const { parseMethodBodies } = require('./java/validater');
|
||||||
const { getTypeInheritanceList } = require('./java/expression-resolver');
|
const { getTypeInheritanceList } = require('./java/expression-resolver');
|
||||||
|
const { Settings } = require('./settings');
|
||||||
|
const { trace, info, time, timeEnd } = require('./logging');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {Map<string, CEIType>} AndroidLibrary
|
* @typedef {Map<string, CEIType>} AndroidLibrary
|
||||||
@@ -76,13 +72,6 @@ function positionAt(index, content) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} s
|
|
||||||
*/
|
|
||||||
function trace(s) {
|
|
||||||
console.log(`${Date.now()}: ${s}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
class JavaDocInfo {
|
class JavaDocInfo {
|
||||||
/**
|
/**
|
||||||
* @param {string} uri
|
* @param {string} uri
|
||||||
@@ -226,7 +215,7 @@ function reparse(uris, opts) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (method_body_uris.length) {
|
if (method_body_uris.length) {
|
||||||
console.time('parse-methods');
|
time('parse-methods');
|
||||||
method_body_uris.forEach(uri => {
|
method_body_uris.forEach(uri => {
|
||||||
const doc = liveParsers.get(uri);
|
const doc = liveParsers.get(uri);
|
||||||
if (!doc || !doc.parsed) {
|
if (!doc || !doc.parsed) {
|
||||||
@@ -234,7 +223,7 @@ function reparse(uris, opts) {
|
|||||||
}
|
}
|
||||||
parseMethodBodies(doc.parsed.unit, typemap);
|
parseMethodBodies(doc.parsed.unit, typemap);
|
||||||
})
|
})
|
||||||
console.timeEnd('parse-methods');
|
timeEnd('parse-methods');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -335,9 +324,12 @@ connection.onInitialize((params) => {
|
|||||||
connection.onInitialized(async () => {
|
connection.onInitialized(async () => {
|
||||||
if (hasConfigurationCapability) {
|
if (hasConfigurationCapability) {
|
||||||
// Register for all configuration changes.
|
// Register for all configuration changes.
|
||||||
connection.client.register(DidChangeConfigurationNotification.type, undefined);
|
connection.client.register(
|
||||||
|
DidChangeConfigurationNotification.type, {
|
||||||
|
section: 'android-dev-ext',
|
||||||
|
});
|
||||||
const initialSettings = await connection.workspace.getConfiguration({
|
const initialSettings = await connection.workspace.getConfiguration({
|
||||||
section: Settings.ID,
|
section: "android-dev-ext"
|
||||||
});
|
});
|
||||||
Settings.set(initialSettings);
|
Settings.set(initialSettings);
|
||||||
}
|
}
|
||||||
@@ -348,7 +340,7 @@ connection.onInitialized(async () => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const src_folder = await getAppRootFolder();
|
const src_folder = await getAppSourceRootFolder();
|
||||||
if (src_folder) {
|
if (src_folder) {
|
||||||
await rescanSourceFolders(src_folder);
|
await rescanSourceFolders(src_folder);
|
||||||
reparse([...liveParsers.keys()], { includeMethods: false, first_parse: true });
|
reparse([...liveParsers.keys()], { includeMethods: false, first_parse: true });
|
||||||
@@ -367,8 +359,8 @@ async function rescanSourceFolders(src_folder) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// when the appRoot config value changes and we rescan the folder, we need
|
// when the appSourceRoot config value changes and we rescan the folder, we need
|
||||||
// to delete any parsers that were from the old appRoot
|
// to delete any parsers that were from the old appSourceRoot
|
||||||
const unused_keys = new Set(liveParsers.keys());
|
const unused_keys = new Set(liveParsers.keys());
|
||||||
|
|
||||||
const files = await loadWorkingFileList(src_folder);
|
const files = await loadWorkingFileList(src_folder);
|
||||||
@@ -398,10 +390,10 @@ async function rescanSourceFolders(src_folder) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to locate the app root folder using workspace folders and the appRoot setting
|
* Attempts to locate the app root folder using workspace folders and the appSourceRoot setting
|
||||||
* @returns Absolute path to app root folder or null
|
* @returns Absolute path to app root folder or null
|
||||||
*/
|
*/
|
||||||
async function getAppRootFolder() {
|
async function getAppSourceRootFolder() {
|
||||||
/** @type {string} */
|
/** @type {string} */
|
||||||
let src_folder = null;
|
let src_folder = null;
|
||||||
|
|
||||||
@@ -412,7 +404,7 @@ async function getAppRootFolder() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
folders.find(folder => {
|
folders.find(folder => {
|
||||||
const main_folder = path.join(folder.uri.replace(/^\w+:\/\//, ''), Settings.appRoot);
|
const main_folder = path.join(folder.uri.replace(/^\w+:\/\//, ''), Settings.appSourceRoot);
|
||||||
try {
|
try {
|
||||||
if (fs.statSync(main_folder).isDirectory()) {
|
if (fs.statSync(main_folder).isDirectory()) {
|
||||||
src_folder = main_folder;
|
src_folder = main_folder;
|
||||||
@@ -425,7 +417,7 @@ async function getAppRootFolder() {
|
|||||||
console.log([
|
console.log([
|
||||||
`Failed to find source root from workspace folders:`,
|
`Failed to find source root from workspace folders:`,
|
||||||
...folders.map(f => ` - ${f.uri}`),
|
...folders.map(f => ` - ${f.uri}`),
|
||||||
'Configure the Android App Root value in your workspace settings to point to your source folder containing AndroidManifest.xml',
|
'Configure the Android App Source Root value in your workspace settings to point to your source folder containing AndroidManifest.xml',
|
||||||
].join(os.EOL));
|
].join(os.EOL));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -438,9 +430,9 @@ async function loadWorkingFileList(src_folder) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
trace(`Using src root folder: ${src_folder}. Searching for Android project source files...`);
|
trace(`Using src root folder: ${src_folder}. Searching for Android project source files...`);
|
||||||
console.time('source file search')
|
time('source file search')
|
||||||
const files = scanSourceFiles(src_folder);
|
const files = scanSourceFiles(src_folder);
|
||||||
console.timeEnd('source file search');
|
timeEnd('source file search');
|
||||||
|
|
||||||
if (!files.find(file => /^androidmanifest.xml$/i.test(file.relfpn))) {
|
if (!files.find(file => /^androidmanifest.xml$/i.test(file.relfpn))) {
|
||||||
console.log(`Warning: No AndroidManifest.xml found in app root folder. Check the Android App Root value in your workspace settings.`)
|
console.log(`Warning: No AndroidManifest.xml found in app root folder. Check the Android App Root value in your workspace settings.`)
|
||||||
@@ -492,16 +484,19 @@ async function loadWorkingFileList(src_folder) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
connection.onDidChangeConfiguration(async (change) => {
|
connection.onDidChangeConfiguration(async (change) => {
|
||||||
trace(`onDidChangeConfiguration`);
|
trace(`onDidChangeConfiguration: ${JSON.stringify(change)}`);
|
||||||
if (change && change.settings && change.settings[Settings.ID]) {
|
const old_app_root = Settings.appSourceRoot;
|
||||||
const old_app_root = Settings.appRoot;
|
const newSettings = await connection.workspace.getConfiguration({
|
||||||
Settings.onChange(change.settings[Settings.ID]);
|
section: "android-dev-ext"
|
||||||
if (old_app_root !== Settings.appRoot) {
|
});
|
||||||
const src_folder = await getAppRootFolder();
|
|
||||||
if (src_folder) {
|
Settings.set(newSettings);
|
||||||
rescanSourceFolders(src_folder);
|
|
||||||
reparse([...liveParsers.keys()]);
|
if (old_app_root !== Settings.appSourceRoot) {
|
||||||
}
|
const src_folder = await getAppSourceRootFolder();
|
||||||
|
if (src_folder) {
|
||||||
|
rescanSourceFolders(src_folder);
|
||||||
|
reparse([...liveParsers.keys()]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -523,7 +518,7 @@ documents.onDidChangeContent((change) => {
|
|||||||
*/
|
*/
|
||||||
async function validateTextDocument(textDocument) {
|
async function validateTextDocument(textDocument) {
|
||||||
if (androidLibrary instanceof Promise) {
|
if (androidLibrary instanceof Promise) {
|
||||||
trace('Waiting for Android Library load');
|
trace('waiting for Android Library load to complete');
|
||||||
androidLibrary = await androidLibrary;
|
androidLibrary = await androidLibrary;
|
||||||
}
|
}
|
||||||
/** @type {ParseProblem[]} */
|
/** @type {ParseProblem[]} */
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
|
|
||||||
const defaultSettings = {
|
const defaultSettings = {
|
||||||
appRoot: 'app/src/main'
|
appSourceRoot: 'app/src/main',
|
||||||
|
trace: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
class AndroidProjectSettings {
|
class AndroidProjectSettings {
|
||||||
@@ -8,24 +9,22 @@ const defaultSettings = {
|
|||||||
* The root of the app source folder.
|
* The root of the app source folder.
|
||||||
* This folder should contain AndroidManifest.xml as well as the asets, res, etc folders
|
* This folder should contain AndroidManifest.xml as well as the asets, res, etc folders
|
||||||
*/
|
*/
|
||||||
appRoot = defaultSettings.appRoot;
|
appSourceRoot = defaultSettings.appSourceRoot;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The identifier for the language server settings
|
* True if we log details
|
||||||
*/
|
*/
|
||||||
ID = 'androidJavaLanguageServer';
|
trace = defaultSettings.trace;
|
||||||
|
|
||||||
|
updateCount = 0;
|
||||||
|
|
||||||
static Instance = new AndroidProjectSettings();
|
static Instance = new AndroidProjectSettings();
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the user edits the settings
|
|
||||||
* @param {*} values
|
|
||||||
*/
|
|
||||||
onChange(values) {
|
|
||||||
this.set(values);
|
|
||||||
}
|
|
||||||
|
|
||||||
set(values) {
|
set(values) {
|
||||||
|
if (!values || typeof values !== 'object') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.updateCount += 1;
|
||||||
console.log(`settings set: ${JSON.stringify(values)}`);
|
console.log(`settings set: ${JSON.stringify(values)}`);
|
||||||
for (let key in defaultSettings) {
|
for (let key in defaultSettings) {
|
||||||
if (Object.prototype.hasOwnProperty.call(values, key)) {
|
if (Object.prototype.hasOwnProperty.call(values, key)) {
|
||||||
@@ -35,20 +34,4 @@ const defaultSettings = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// function getDocumentSettings(resource) {
|
|
||||||
// if (!hasConfigurationCapability) {
|
|
||||||
// return Promise.resolve(projectSettings);
|
|
||||||
// }
|
|
||||||
// let result = documentSettings.get(resource);
|
|
||||||
// if (!result) {
|
|
||||||
// result = connection.workspace.getConfiguration({
|
|
||||||
// scopeUri: resource,
|
|
||||||
// section: 'androidJavaLanguageServer',
|
|
||||||
// });
|
|
||||||
// documentSettings.set(resource, result);
|
|
||||||
// }
|
|
||||||
// return result;
|
|
||||||
// }
|
|
||||||
|
|
||||||
exports.Settings = AndroidProjectSettings.Instance;
|
exports.Settings = AndroidProjectSettings.Instance;
|
||||||
|
|||||||
21
package.json
21
package.json
@@ -31,13 +31,24 @@
|
|||||||
"contributes": {
|
"contributes": {
|
||||||
"configuration": {
|
"configuration": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"title": "Java (Android)",
|
"title": "Android",
|
||||||
"properties": {
|
"properties": {
|
||||||
"androidJavaLanguageServer.maxNumberOfProblems": {
|
"android-dev-ext.appSourceRoot": {
|
||||||
"scope": "resource",
|
"scope": "resource",
|
||||||
"type": "number",
|
"type": "string",
|
||||||
"default": 100,
|
"default": "app/src/main",
|
||||||
"description": "Controls the maximum number of problems produced by the server."
|
"description": "Relative path to the app source files. This folder should contain AndroidManifest.xml."
|
||||||
|
},
|
||||||
|
"android-dev-ext.subscriptionKey": {
|
||||||
|
"scope": "application",
|
||||||
|
"type": "string",
|
||||||
|
"default": ""
|
||||||
|
},
|
||||||
|
"android-dev-ext.trace": {
|
||||||
|
"scope": "resource",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"description": "Enable detailed trace logging."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user