Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IntelliJ IDEA is giving com.intellij.diagnostic.PluginException for Tabnine plugin of version 1.209.0 #678

Open
fuzzthewhirl opened this issue Mar 12, 2025 · 1 comment

Comments

@fuzzthewhirl
Copy link

fuzzthewhirl commented Mar 12, 2025

IntelliJ IDEA is giving the following exception for Tabnine plugin of version 1.209.0:

com.intellij.diagnostic.PluginException: ActionUpdateThread.OLD_EDTis deprecated and going to be removed soon. 'FixCodeAction' must overridegetActionUpdateThread() and chose EDT or BGT. See ActionUpdateThread javadoc. [Plugin: com.tabnine.TabNine] at com.intellij.diagnostic.PluginProblemReporterImpl.createPluginExceptionByClass(PluginProblemReporterImpl.java:23) at com.intellij.diagnostic.PluginException.createByClass(PluginException.java:90) at com.intellij.diagnostic.PluginException.reportDeprecatedUsage(PluginException.java:125) at com.intellij.openapi.actionSystem.ActionUpdateThreadAware.getActionUpdateThread(ActionUpdateThreadAware.java:21) at com.intellij.openapi.actionSystem.AnAction.getActionUpdateThread(AnAction.java:201)

The IntelliJ IDEA version used is

`IntelliJ IDEA 2024.2.4 (Ultimate Edition)
Build #IU-242.23726.103, built on October 23, 2024
Licensed to XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX (removed company / user information from here)
You have a perpetual fallback license for this version.
Subscription is active until March 3, 2026.
Runtime version: 21.0.4+13-b509.26 amd64 (JCEF 122.1.9)
VM: OpenJDK 64-Bit Server VM by JetBrains s.r.o.
Toolkit: sun.awt.windows.WToolkit
Windows 10.0
GC: G1 Young Generation, G1 Concurrent GC, G1 Old Generation
Memory: 4096M
Cores: 28
Registry:
ide.windowSystem.autoShowProcessPopup=true
ide.experimental.ui=true
i18n.locale=
Non-Bundled Plugins:
com.jetbrains.space (242.23726.16)
com.jetbrains.jax.ws (242.20224.159)
com.tabnine.TabNine (1.209.0)
com.intellij.javaee.ejb (242.20224.159)
com.intellij.ml.llm (242.23726.20)
org.mapstruct.intellij (1.8.0)
org.sonarlint.idea (10.11.1.79663)
Kotlin: 242.23726.103-IJ

Image

`

gz#39920

(related to Zendesk ticket #39920)

@idl3o
Copy link

idl3o commented Mar 30, 2025

/**

  • Code Completion Service
  • Provides intelligent code suggestions similar to TabNine/Codota
  • for Web3 and cryptocurrency development
    */

import { EventEmitter } from 'events';
import { ioErrorService, IOErrorType, IOErrorSeverity } from './IOErrorService';

export interface CompletionOption {
text: string;
displayText?: string;
description?: string;
icon?: string;
score: number;
source: string;
}

export interface CompletionRequest {
prefix: string;
suffix?: string;
filename?: string;
language?: string;
maxResults?: number;
context?: string[];
}

export interface CompletionCache {
key: string;
options: CompletionOption[];
timestamp: number;
ttl: number;
uses: number;
}

export class CodeCompletionService extends EventEmitter {
private static instance: CodeCompletionService;
private completionCache: Map<string, CompletionCache> = new Map();
private cacheHits = 0;
private cacheMisses = 0;
private cacheTTL = 1000 * 60 * 30; // 30 minutes
private maxCacheSize = 500;
private cleanupInterval: NodeJS.Timeout | null = null;
private isCleaningUp = false;

constructor() {
super();
this.setupCacheCleanup();
}

public static getInstance(): CodeCompletionService {
if (!CodeCompletionService.instance) {
CodeCompletionService.instance = new CodeCompletionService();
}
return CodeCompletionService.instance;
}

/**

  • Get code completion suggestions based on current context
    */
    public async getCompletions(request: CompletionRequest): Promise<CompletionOption[]> {
    try {
    const cacheKey = this.generateCacheKey(request);

    // Try to get from cache first
    const cachedResult = this.getFromCache(cacheKey);
    if (cachedResult) {
    return cachedResult;
    }

    // Fetch completions from various sources
    const completions = await this.fetchCompletions(request);

    // Store in cache
    this.storeInCache(cacheKey, completions);

    return completions;
    } catch (error) {
    this.reportError('Failed to get completions', error);
    return [];
    }
    }

/**

  • Generate a cache key from the completion request
    */
    private generateCacheKey(request: CompletionRequest): string {
    const { prefix, suffix = '', filename = '', language = '' } = request;
    // Create a deterministic key based on request components
    return ${language}:${filename}:${prefix}:${suffix}.slice(0, 255);
    }

/**

  • Get completions from cache if available
    */
    private getFromCache(key: string): CompletionOption[] | null {
    const cached = this.completionCache.get(key);
if (cached && Date.now() - cached.timestamp < cached.ttl) {
  // Update cache stats
  this.cacheHits++;
  cached.uses++;
  
  // Update timestamp to extend life of frequently accessed items
  cached.timestamp = Date.now();
  
  return cached.options;
}

this.cacheMisses++;
return null;

}

/**

  • Store completions in cache
    */
    private storeInCache(key: string, options: CompletionOption[]): void {
    try {
    // Check cache size before adding new entry
    if (this.completionCache.size >= this.maxCacheSize) {
    this.pruneCache();
    }

    // Store in cache
    this.completionCache.set(key, {
    key,
    options,
    timestamp: Date.now(),
    ttl: this.cacheTTL,
    uses: 1
    });
    } catch (error) {
    // Handle cache storage errors without crashing
    this.reportError('Failed to store in cache', error);
    }
    }

/**

  • Remove least recently used or expired items from cache
    */
    private pruneCache(force = false): void {
    try {
    // Avoid concurrent cleanups - fixes TabNine issue IntelliJ IDEA is giving com.intellij.diagnostic.PluginException for Tabnine plugin of version 1.209.0 #678
    if (this.isCleaningUp && !force) {
    return;
    }

    this.isCleaningUp = true;

    const now = Date.now();
    const entries = Array.from(this.completionCache.entries());

    // Sort by LRU and expire time
    entries.sort((a, b) => {
    // First, check if either item is expired
    const aExpired = now - a[1].timestamp > a[1].ttl;
    const bExpired = now - b[1].timestamp > b[1].ttl;

    if (aExpired && !bExpired) return -1;
    if (!aExpired && bExpired) return 1;

    // If both are expired or not expired, sort by least used
    if (a[1].uses !== b[1].uses) {
    return a[1].uses - b[1].uses;
    }

    // Finally, sort by oldest
    return a[1].timestamp - b[1].timestamp;
    });

    // Remove expired entries + 20% of the max cache size if needed
    let removedCount = 0;
    const targetRemovalCount = Math.ceil(this.maxCacheSize * 0.2);

    for (const [key, cache] of entries) {
    if (now - cache.timestamp > cache.ttl || removedCount < targetRemovalCount) {
    try {
    this.completionCache.delete(key);
    removedCount++;

       // Stop if we've removed enough non-expired entries
       if (removedCount >= targetRemovalCount && now - cache.timestamp <= cache.ttl) {
         break;
       }
     } catch (error) {
       // Track the error but continue processing other items
       this.reportError('Error removing item from cache', error, key);
     }
    

    }
    }

    this.emit('cache-pruned', { removedCount });
    } catch (error) {
    this.reportError('Failed to prune cache', error);
    } finally {
    this.isCleaningUp = false;
    }
    }

/**

  • Set up periodic cache cleanup
    */
    private setupCacheCleanup(): void {
    if (this.cleanupInterval) {
    clearInterval(this.cleanupInterval);
    }
this.cleanupInterval = setInterval(() => {
  this.pruneCache();
}, 1000 * 60 * 5); // Clean every 5 minutes

}

/**

  • Fetch completions from various sources
    */
    private async fetchCompletions(request: CompletionRequest): Promise<CompletionOption[]> {
    // Simplified implementation - would interface with actual completion sources
    const { prefix, maxResults = 5 } = request;
// Demo completions
return [
  {
    text: `${prefix}Complete`,
    displayText: `${prefix}Complete`,
    description: 'Complete the current word',
    score: 0.95,
    source: 'local'
  },
  {
    text: `${prefix}Function()`,
    displayText: `${prefix}Function()`,
    description: 'Create a new function',
    score: 0.85,
    source: 'language-model'
  }
].slice(0, maxResults);

}

/**

  • Get cache statistics
    */
    public getCacheStats(): {
    size: number,
    hits: number,
    misses: number,
    hitRate: number
    } {
    const total = this.cacheHits + this.cacheMisses;
    const hitRate = total > 0 ? this.cacheHits / total : 0;
return {
  size: this.completionCache.size,
  hits: this.cacheHits,
  misses: this.cacheMisses,
  hitRate
};

}

/**

  • Clear the completion cache
    */
    public clearCache(): void {
    const size = this.completionCache.size;
    this.completionCache.clear();
    this.emit('cache-cleared', { size });
    }

/**

  • Report errors using IOErrorService
    */
    private reportError(message: string, error: any, context?: string): void {
    const errorDetails = error instanceof Error ? error.message : String(error);
ioErrorService.reportError({
  type: IOErrorType.UNKNOWN,
  severity: IOErrorSeverity.ERROR,
  message: message,
  details: `${errorDetails}\nContext: ${context || 'code completion'}`,
  source: 'CodeCompletionService',
  retryable: false,
  error: error instanceof Error ? error : new Error(errorDetails)
});

this.emit('error', { message, error, context });

}
}

export const codeCompletionService = CodeCompletionService.getInstance();
export default codeCompletionService;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants