Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions data/working_smells_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,15 +58,15 @@
"threshold": {
"label": "Threshold",
"description": "Defines a threshold for triggering this smell.",
"value": 9
"value": 3
}
}
},
"long-element-chain": {
"message_id": "LEC001",
"name": "Long Element Chain (LEC)",
"acronym": "LEC",
"enabled": true,
"enabled": false,
"smell_description": "Chained element access can be inefficient in large structures, increasing access time and CPU effort, thereby consuming more energy.",
"analyzer_options": {
"threshold": {
Expand All @@ -80,7 +80,7 @@
"message_id": "CRC001",
"name": "Cached Repeated Calls (CRC)",
"acronym": "CRC",
"enabled": true,
"enabled": false,
"smell_description": "Failing to cache repeated expensive calls leads to redundant computation, which wastes CPU cycles and drains energy needlessly.",
"analyzer_options": {
"threshold": {
Expand All @@ -98,4 +98,4 @@
"smell_description": "String concatenation in loops creates new objects each time, increasing memory churn and CPU workload, which leads to higher energy consumption.",
"analyzer_options": {}
}
}
}
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

45 changes: 23 additions & 22 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,11 @@
},
"views": {
"ecooptimizer": [
{
"id": "ecooptimizer.dashboardView",
"name": "Energy Dashboard",
"icon": "assets/eco-icon.png"
},
{
"id": "ecooptimizer.refactorView",
"name": "Refactoring Details",
Expand All @@ -155,11 +160,6 @@
"name": "Code Smells",
"icon": "assets/eco-icon.png"
},
{
"id": "ecooptimizer.metricsView",
"name": "Carbon Metrics",
"icon": "assets/eco-icon.png"
},
{
"id": "ecooptimizer.filterView",
"name": "Filter Smells",
Expand All @@ -179,8 +179,8 @@
"when": "!workspaceState.workspaceConfigured"
},
{
"view": "ecooptimizer.metricsView",
"contents": "No energy savings to declare. Configure your workspace to start saving energy!\n\n[Configure Workspace](command:ecooptimizer.configureWorkspace)\n\n[Read the docs](https://code.visualstudio.com/api) to learn how to use Eco-Optimizer.",
"view": "ecooptimizer.dashboardView",
"contents": "Welcome to the Energy Dashboard! Configure your workspace to start tracking refactoring statistics and energy savings.\n\n[Configure Workspace](command:ecooptimizer.configureWorkspace)\n\n[Read the docs](https://github.com/ssm-lab/capstone--sco-vs-code-plugin/wiki) to learn how to use Eco-Optimizer.",
"when": "!workspaceState.workspaceConfigured"
}
],
Expand Down Expand Up @@ -255,6 +255,12 @@
"icon": "$(tools)",
"category": "Eco"
},
{
"command": "ecooptimizer.refactorAllSmells",
"title": "Refactor All Smells",
"icon": "$(wrench)",
"category": "Eco"
},
{
"command": "ecooptimizer.refactorSmell",
"title": "Refactor Smell",
Expand All @@ -279,13 +285,8 @@
"category": "Eco"
},
{
"command": "ecooptimizer.clearMetricsData",
"title": "Clear Metrics Data",
"category": "Eco"
},
{
"command": "ecooptimizer.metricsView.refresh",
"title": "Refresh Metrics Data",
"command": "ecooptimizer.dashboardView.refresh",
"title": "Refresh Dashboard",
"icon": "$(sync)",
"category": "Eco"
},
Expand Down Expand Up @@ -337,17 +338,12 @@
},
{
"command": "ecooptimizer.exportMetricsData",
"when": "view == ecooptimizer.metricsView",
"group": "resource"
},
{
"command": "ecooptimizer.clearMetricsData",
"when": "view == ecooptimizer.metricsView",
"when": "view == ecooptimizer.dashboardView",
"group": "resource"
},
{
"command": "ecooptimizer.metricsView.refresh",
"when": "view == ecooptimizer.metricsView",
"command": "ecooptimizer.dashboardView.refresh",
"when": "view == ecooptimizer.dashboardView",
"group": "navigation"
}
],
Expand All @@ -372,6 +368,11 @@
"when": "view == ecooptimizer.smellsView && viewItem == file_with_smells && !refactoringInProgress",
"group": "inline"
},
{
"command": "ecooptimizer.refactorAllSmells",
"when": "view == ecooptimizer.smellsView && viewItem == file_with_smells && !refactoringInProgress",
"group": "inline"
},
{
"command": "ecooptimizer.refactorSmell",
"when": "view == ecooptimizer.smellsView && viewItem == smell && !refactoringInProgress",
Expand Down
68 changes: 61 additions & 7 deletions src/api/backend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ export async function initLogs(log_dir: string): Promise<boolean> {
* - Response contains invalid data format
*/
export async function fetchSmells(
projectRoot: string,
filePath: string,
enabledSmells: Record<string, Record<string, number | string>>,
): Promise<{ smells: Smell[]; status: number }> {
Expand All @@ -99,6 +100,7 @@ export async function fetchSmells(

try {
ecoOutput.debug(`[backend.ts] Request payload for ${fileName}:`, {
project_root: projectRoot,
file_path: filePath,
enabled_smells: enabledSmells
});
Expand All @@ -109,6 +111,7 @@ export async function fetchSmells(
'Content-Type': 'application/json',
},
body: JSON.stringify({
project_root: projectRoot,
file_path: filePath,
enabled_smells: enabledSmells,
}),
Expand Down Expand Up @@ -185,7 +188,7 @@ export async function backendRefactorSmell(
}

ecoOutput.info(`[backend.ts] Starting refactoring for smell: ${smell.symbol}`);
console.log('Starting refactoring for smell:', smell);
console.log('Starting refactoring for smell:', smell, "in workspace:", workspacePath);

try {
const response = await fetch(url, {
Expand Down Expand Up @@ -223,12 +226,11 @@ export async function backendRefactorSmell(
* @returns A promise resolving to the refactored data or throwing an error if unsuccessful.
*/
export async function backendRefactorSmellType(
smell: Smell,
workspacePath: string
workspacePath: string,
smellType: string,
filePath: string,
): Promise<RefactoredData> {
const url = `${BASE_URL}/refactor-by-type`;
const filePath = smell.path;
const smellType = smell.symbol;

// Validate workspace configuration
if (!workspacePath) {
Expand All @@ -242,7 +244,7 @@ export async function backendRefactorSmellType(
const payload = {
sourceDir: workspacePath,
smellType,
firstSmell: smell,
targetFile: filePath,
};

try {
Expand All @@ -261,7 +263,59 @@ export async function backendRefactorSmellType(
}

const result = await response.json();
ecoOutput.info(`[backend.ts] Refactoring successful for ${smell.symbol}`);
ecoOutput.info(`[backend.ts] Refactoring successful for ${smellType}`);
return result;

} catch (error: any) {
ecoOutput.error(`[backend.ts] Refactoring error: ${error.message}`);
throw new Error(`Refactoring failed: ${error.message}`);
}
}

/**
* Sends a request to the backend to refactor all smells of a type.
*
* @param smell - The smell to refactor.
* @param workspacePath - The path to the workspace.
* @returns A promise resolving to the refactored data or throwing an error if unsuccessful.
*/
export async function backendRefactorSmellAll(
workspacePath: string,
filePath: string,
): Promise<RefactoredData> {
const url = `${BASE_URL}/refactor-all`;

// Validate workspace configuration
if (!workspacePath) {
ecoOutput.error('[backend.ts] Refactoring aborted: No workspace path');
throw new Error('No workspace path provided');
}

ecoOutput.info(`[backend.ts] Starting refactoring for all smells in "${filePath}"`);

// Prepare the payload for the backend
const payload = {
sourceDir: workspacePath,
targetFile: filePath,
};

try {
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(payload),
});

if (!response.ok) {
const errorData = await response.json();
ecoOutput.error(`[backend.ts] Refactoring failed: ${errorData.detail || 'Unknown error'}`);
throw new Error(errorData.detail || 'Refactoring failed');
}

const result = await response.json();
ecoOutput.info(`[backend.ts] Refactoring successful for all smells`);
return result;

} catch (error: any) {
Expand Down
3 changes: 3 additions & 0 deletions src/commands/configureWorkspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ function findPythonFoldersRecursively(folderPath: string): string[] {
// Validate current folder contains Python artifacts
if (
files.includes('__init__.py') ||
files.includes('setup.py') ||
files.includes('pyproject.toml') ||
files.includes('requirements.txt') ||
files.some((file) => file.endsWith('.py'))
) {
hasPythonFiles = true;
Expand Down
15 changes: 13 additions & 2 deletions src/commands/detection/detectSmells.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { ecoOutput } from '../../extension';
* @param smellsCacheManager - Manager for cached smell results
*/
export async function detectSmellsFile(
projectRoot: string,
filePath: string,
smellsViewProvider: SmellsViewProvider,
smellsCacheManager: SmellsCacheManager,
Expand All @@ -38,7 +39,11 @@ export async function detectSmellsFile(

try {
ecoOutput.info(`[detection.ts] Analyzing: ${path.basename(filePath)}`);
const { smells, status } = await fetchSmells(filePath, enabledSmellsForBackend);
const { smells, status } = await fetchSmells(
projectRoot,
filePath,
enabledSmellsForBackend,
);

// Handle backend response
if (status === 200) {
Expand Down Expand Up @@ -136,6 +141,7 @@ async function precheckAndMarkQueued(
* @param smellsCacheManager - Manager for cached smell results
*/
export async function detectSmellsFolder(
projectRoot: string,
folderPath: string,
smellsViewProvider: SmellsViewProvider,
smellsCacheManager: SmellsCacheManager,
Expand Down Expand Up @@ -186,7 +192,12 @@ export async function detectSmellsFolder(

// Process each found Python file
for (const file of pythonFiles) {
await detectSmellsFile(file, smellsViewProvider, smellsCacheManager);
await detectSmellsFile(
projectRoot,
file,
smellsViewProvider,
smellsCacheManager,
);
}
},
);
Expand Down
23 changes: 22 additions & 1 deletion src/commands/refactor/acceptRefactoring.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,15 +54,35 @@ export async function acceptRefactoring(
ecoOutput.info(`[refactorActions.ts] Updated affected file: ${file.original}`);
});

const ecoRoot = context.workspaceState.get<string>(
envConfig.WORKSPACE_CONFIGURED_PATH!,
)!;

const tempUpdatedEnergySmells = vscode.Uri.joinPath(
vscode.Uri.file(ecoRoot),
'__ecocache__',
'energy_smells.temp.json',
).fsPath;

const updatedEnergySmells = vscode.Uri.joinPath(
vscode.Uri.file(ecoRoot),
'__ecocache__',
'energy_smells.updated.json',
).fsPath;

fs.copyFileSync(tempUpdatedEnergySmells, updatedEnergySmells);
fs.unlinkSync(tempUpdatedEnergySmells);
ecoOutput.debug('[refactorActions.ts] Updated energy smells data');

// Update metrics if energy savings data exists
if (
refactoringDetailsViewProvider.energySaved &&
refactoringDetailsViewProvider.targetSmell
) {
metricsDataProvider.updateMetrics(
targetFile.original,
refactoringDetailsViewProvider.energySaved,
refactoringDetailsViewProvider.targetSmell.symbol,
refactoringDetailsViewProvider.energySaved,
);
ecoOutput.info('[refactorActions.ts] Updated energy savings metrics');
}
Expand All @@ -83,6 +103,7 @@ export async function acceptRefactoring(
});

await detectSmellsFile(
context.workspaceState.get<string>(envConfig.WORKSPACE_CONFIGURED_PATH!)!,
targetFile.original,
smellsViewProvider,
smellsCacheManager,
Expand Down
Loading
Loading