Skip to content

codeEEmoji is a Java programming plugin created for Intellij Idea. In the context of code augmentation, the plugin provides additional sets of inlay hints. The new inlay hints assist the developer in an original approach by using emojis.

License

Notifications You must be signed in to change notification settings

codeemoji/codeemoji-plugin

Repository files navigation

codEEmoji Plugin

codeEEmoji is a plugin made for Intellij Idea and useful for Java programming. The plugin defines new sets of inlay hints in the context of code augmentation. The new inlay hints use emojis in an innovative way to help the developer. Emojis are displayed for anti-pattern cases such as naming violations or bad programming practices. The plugin can also show emojis in the editor indicating the presence of modifiers for classes, fields, methods, parameters or local variables that are being used. Likewise, the developer can indicate emojis to display for all these elements, according to a rule, for example, for a class being instantiated that implements a specific interface, for a method being invoked that is annotated by a certain annotation , a local variable of a given type, and so on. Furthermore, the plugin has the capability to display implicit annotations for the JakartaEE and Spring frameworks.

demo.mp4

Setup and Use

Prerequisites

How to Install

Via marketplace

JetBrains Marketplace - codEEmoji

How to Download

Manual Installation

  • Download the latest release zip file available from Releases.

How to Download

  • Open Intellij IDEA and navigate to "File>Settings>Plugins" menu. Click on the gear icon and the "* *Install Plugin From Disk..." option. Select the downloaded zip file and click "OK**".

How to Install

  • Restart IDE.

How to Configure

The plugin creates new Inlay hints. All new inlay hints are enabled by default when installing the plugin. To disable inlay hints or configure options that are available for each one, go to "File>Settings>Editor>Inlay Hints". Click "Other>Java".

How to Configure

Global Configuration

The service allows the use of an ExternalService to retrieve data about the project from external sources. The use of this service is transversal to the plugin and can slow down its performance. Currently, the only concrete implementation of inlay provider actively using this service is the Vulnerable Dependency Detector, which uses the external service to retrieve information about known vulnerabilities in project libraries.

If you want to deactivate the use of the external service:

  1. Navigate to "File>Settings>Plugins>codEEmoji Settings".
  2. Deactivate the option as shown in the figure below:

External Service Configuration

Secondary Scanner and API_TOKEN Configuration

The vulnerability scanner allows users to choose between two different scanners for inspecting project dependencies:

  1. Default Scanner: OSV.dev scanner (Documentation: OSV.dev)
  2. Secondary Scanner: Sonatype OSS Index scanner (Documentation: OSS Index)

Our analysis showed that the two scanners present some discrepancies in their results, but neither consistently outperforms the other. If you wish to use the secondary scanner (Sonatype OSS Index), it's important to note that the number of requests to the API service is limited.

To increase this limit:

  1. Create an API_TOKEN:

    • Access OSS Index and create a new account.
    • Navigate to the account settings and click on "Generate API Token".
    • Copy the API_TOKEN to your clipboard.
  2. Configure the plugin:

    • In your IDE, navigate to the plugin global settings.
    • Here you can activate/deactivate the use of the secondary service and insert the new token.

New Global Configuration Interface

Cases of Naming Violation

Short Descriptive Name

Instead of a descriptive name, the variable's name consists of a few letters.

Configuration options: Number of letters

Impacted identifiers: Fields, Method Parameters and Local Variables

Short Descriptive Name

Getter More Than Accessor

A getter that doesn't just return the corresponding attribute but also takes other actions. Adapted from Arnaoudova et al.(2016).

Impacted identifiers: Method Names

Getter More Than Accessor

Is Returns More Than a Boolean

A method's name is a predicate that denotes a true/false value that will be returned. The return type, however, is a more complex type than boolean. Adapted from Arnaoudova et al.(2016).

Impacted identifiers: Method Names

Is Returns More Than a Boolean

Setter Method Returns

A setter method that has a return type other than void. Adapted from Arnaoudova et al.(2016).

Impacted identifiers: Method Names

Setter Method Returns

Expecting But Not Getting a Single Instance

Despite the fact that a method's name suggests it will return a single object, it will actually return a collection. Adapted from Arnaoudova et al.( 2016).

Impacted identifiers: Method Names

Expecting But Not Getting a Single Instance

Validation Method Does Not Confirm

A validation method (such as one with the words validate, check, or ensure) does not confirm the validation; that is, it neither provides a return value indicating whether the validation was successful. Adapted from Arnaoudova et al.(2016).

Impacted identifiers: Method Names

Validation Method Does Not Confirm

Getter Does Not Return

When a method's name begins with get or return, for example, it might be assumed that it returns something, but the return type is actually void. Adapted from Arnaoudova et al.(2016).

Impacted identifiers: Method Names

Getter Does Not Return

Not Answered Question

A method's name takes the form of a predicate, but its return type is not boolean. Adapted from Arnaoudova et al.(2016).

Impacted identifiers: Method Names

Not Answered Question

Transform Method Does Not Return

While there is no return value, a method's name implies that an object has been transformed. Adapted from Arnaoudova et al.(2016).

Impacted identifiers: Method Names

Transform Method Does Not Return

Expecting But Not Getting a Collection

Even though a method's name suggests a collection should be returned, nothing or just one object is instead given. Adapted from Arnaoudova et al.( 2016).

Impacted identifiers: Method Names

Expecting But Not Getting a Collection

Says One But Contains Many

An attribute's type suggests that it stores a collection of objects, contrary to the name, which suggests a single instance. Adapted from Peruma et al.(2021).

Impacted identifiers: Fields, Method Parameters and Local Variables

Says One But Contains Many

Name Suggests Boolean By Type Does Not

An attribute's name implies that its value is true or false, yet its defining type is not boolean. Adapted from Arnaoudova et al.(2016).

Impacted identifiers: Fields, Method Parameters and Local Variables

Name Suggests Boolean By Type Does Not

Says Many But Contains One

The name of an attribute suggests multiple instances, but its type suggests a single one. Adapted from Arnaoudova et al.(2016).

Impacted identifiers: Fields, Method Parameters and Local Variables

Says Many But Contains One

Name Contains Only Special Characters

The identifier's name is made up entirely of non-alphanumeric characters. Adapted from Arnaoudova et al.(2016).

Impacted identifiers: Fields, Method Parameters and Local Variables

Name Contains Only Special Character

Cases of Showing Modifiers

This inlay hint allows you to configure the display of emojis for class, field and method modifiers. Emojis are displayed when an element is used in the code, indicating its modifiers. The figure below shows the configuration screen with the options enabled during installation. Then a code snippet is displayed, where all options have been enabled.

Impacted identifiers: Classes, Fields and Methods

Showing Modifiers

Showing Modifiers - Sample

Cases of Showing Specifics of Projects

This inlay hint is displayed according to the specifics of the project. It must be configured by the developer from a file in the root of the project named "codeemoji.json". It allows indicating rules for displaying emojis according to specific features for each element, as follows:

  • Element: Class
    • Features: Annotations, Extends and Implements
  • Element: Field
    • Features: Annotations, Types
  • Element: Method
    • Features: Annotations, Returns, Packages
  • Element: Parameter
    • Features: Annotations, Types
  • Element: Local Variable
    • Features: Annotations, Types

For each element, it is possible to optionally indicate an emoji from the unicode sequence that represents it. The " codeemoji.json" file follows a simple description pattern, as shown in the following a partial example:

Showing Specifics for the Projects - File Sample

Complete example here.

In the configuration screen of this inlay hint, the rules currently defined for the open project are displayed. See the following figure.

Showing Specifics for the Projects - Configuration

Here's an example of usage from a code snipped:

Showing Specifics for the Projects - Code Sample

Cases of Showing Implicit Annotations

Unlike other cases, this inlay hint is useful for displaying implicit annotations when frameworks are used. It can be displayed for an entirely implicit annotation, for implicit annotation parameters, or even for implicit values for annotation parameters.

Implicit information is understood to be information that is optional, but with a different standard value. For example, a class mapped with @Entity will have @Column implicit for almost all fields (restrictions apply), where the name parameter of the annotation will have the name of the field as its value.

So far the plugin implements some JPA mapping annotations (Java Persistence API - javax and jakarta packages), and some useful Spring framework annotations.

In the configuration screen of this inlay hint, the annotations currently implemented by plugin are displayed. See the following figure.

Showing Implicit Annotations - Configuration

Here's an example of usage with JPA from a code snipped:

Showing Implicit Annotations - Example

Here's an examples of usage with Spring from a code snipped:

Showing Implicit Annotations - Example

Showing Implicit Annotations - Example

Cases of Structural Analysis

The plugin also incorporates implementations of inlay hints that are used to display structural characteristics of syntactic elements in order to deduce implicit information contained in them. The visual aid provided by such hints can facilitate the creation of complex code where the programmer is required to contextualize otherwise difficultly inferable knowledge. A subset of these implementations specifically concerns the calculation of code complexity metrics that help determining the difficulty level in understanding and maintaining code.

Code Complexity

The computed code complexity metrics encompass the total number of methods per class, the cyclomatic complexity per number of lines of code in a method, the total number of identifiers per method and the total number of lines per method. Each one of them has a predetermined but configurable threshold which, if exceeded, triggers the addition of an inlay hint displaying a warning.

High Cyclomatic Complexity Method

A code complexity metric that, based on a configurable threshold, indicates whether a method has a "very high" number of linearly independent paths with respect to the number of lines in it.

The algorithm for calculating the metric is adapted from the specification defined by Watson and McCabe ("Structured Testing: A Testing Methodology Using the Cyclomatic Complexity Metric", 1996). Starting from a value S := 1, the code elements present in the method are analyzed to match keywords that create a decision point, therefore, triggering the addition of a new path, which, in turn, entails increasing S by a factor of 1. The keywords and operators considered in such analysis do not allow the inspection single multi-way branch statements (eg. if a switch statement is recognized, only add 1 to S for each case label); they are the following:

  • "&&" and "||"
  • "if" and "else if"
  • "case"
  • "for" and "while"
  • "try"

The default value for this metric is set to 0.36 Cyclomatic Complexity / Lines of Code, which corresponds to the statistical threshold cited by Lanza and Marinescu ("Object-Oriented Metrics in Practice", 2006).

Notice that the calculation is triggered once the method exceeds the thresholds for the cyclomatic complexity and the line count, which are both set to 1 by default. The line count does not include any superfluous lines covered by comments.

Inlay hint information
Emoji 🧩
Impacted identifiers Method names
Configuration
High Cyclomatic Complexity Method - Configuration
High Cyclomatic Complexity Method - Configuration
High Cyclomatic Complexity Method - Configuration
Set custom thresholds by opening the settings/preferences and navigating to: Editor → Inlay Hints → Other → Java → High Cyclomatic Complexity Method.
Example
High Cyclomatic Complexity Method - Example
The method shown above has a cyclomatic complexity of 15. Such number is obtained by summing the amount of the matching keywords and operations from sections 0 trough 5. The method also spans over 34 lines of code (excluding those covered by comments), from line 6 to line 44. The rounded ratio between these two numbers equals to 0.44 cyclomatic complexity / lines of code. The plugin displays the inlay hint if the threshold is set to a value smaller than or equal to such amount.

Large Identifier Count Method

A code complexity metric that indicates whether a method contains a "very high" number of identifiers based on a configurable threshold.

An identifier indicates a lexical token that associates a symbolic name to a Java syntax entity. For instance, some of the entities an identifier might denote include: variables, data types, classes or methods.

The default value is set to 70 Identifiers / Method.

Inlay hint information
Emoji 📚
Impacted identifiers Method names
Configuration
Large Identifier Count Method - Configuration
Set a custom threshold by opening the settings/preferences and navigating to Editor → Inlay Hints → Other → Java → Large Identifier Count Method.
Example
Large Identifier Count Method - Example
The method shown above contains 70 identifiers. The plugin displays the inlay hint if the threshold is set to a value smaller than or equal to such amount.

Large Line Count Method

A code complexity metric that indicates whether a method contains a "very high" number of lines of code based on a configurable threshold.

The default value is set to 20 Lines of Code / Method, which corresponds to the rounded up statistical threshold of 19.5 Lines of Code / Method cited by Lanza and Marinescu ("Object-Oriented Metrics in Practice", 2006).

Notice that the default calculation also includes any lines covered by comments; the additional padding created by them can be excluded in the configuration.

Inlay hint information
Emoji 🐘
Impacted identifiers Method names
Configuration
Large Line Count Method - Configuration
Large Line Count Method - Configuration
Choose whether comments should be included in the calculation and set a custom threshold by opening the settings/preferences and navigating to Editor → Inlay Hints → Other → Java → Large Line Count Method.
Example
Large Line Count Method - Example
The method shown above spans over 38 lines of code. The plugin displays the inlay hint if the threshold is set to a value smaller than or equal to such amount.

Large Method Count Class

A code complexity metric that indicates whether a class contains a "very high" number of methods based on a configurable threshold.

The default value is set to 15 Methods/Class, which corresponds to the statistical threshold cited by Lanza and Marinescu ("Object-Oriented Metrics in Practice", 2006).

Inlay hint information
Emoji 🐘
Impacted identifiers Class names
Configuration
Large Method Count Class - Configuration
Set a custom threshold by opening the settings/preferences and navigating to Editor → Inlay Hints → Other → Java → Large Method Count Class.*
Example
Large Method Count Class - Example
The class shown above contains 16 methods. The plugin displays the inlay hint if the threshold is set to a value smaller than or equal to such amount.

Methods

Aside from recognizing state-independent and state-changing methods, the structural analysis of methods also foresees the detection of purely defined getters and setters as well as the identification of calls to external functionality.

External Functionality Invoking Method

A method invoking external functionality contains calls to methods defined outside the source roots of the project currently opened in the editor (see IntelliJ "content roots"). Additionally, any method originating from a class or interface belonging to a Java core library (inside a "java.*" package) is excluded from the analysis.

Note that each method call can be followed recursively until its original caller is reached. If any method on the invocation path to the root invoker matches the criteria specified above, the method being currently analyzed is marked with a hint indicating its external source. Since this might be a costly operation for methods comprising many method calls, this option is turned off by default in the IDE's corresponding Inlay Hint settings menu.

Inlay hint information
Emoji 👽
Impacted identifiers Method names
Configuration
External Functionality Invoking Method - Configuration
Set the "Follow method calls and recursively check externality" flag by opening the settings/preferences and navigating to Editor → Inlay Hints → Other → Java → External Functionality Invoking Method.
Example 1
External Functionality Invoking Method - Example 1
"Follow method calls and recursively check externality" flag is checked.
Example 2
External Functionality Invoking Method - Example 2
"Follow method calls and recursively check externality" flag is not set.

Pure Getter Method

Also known as "getter", a pure accessor method only contains one statement that returns a field which must be defined within the same class the method is defined in.

The application of the standard JavaBeans naming convention on the signature's name can be enforced by selecting or deselecting a checkbox in the IDE's corresponding Inlay Hint settings menu.

Inlay hint information
Emoji 📤
Impacted identifiers Method names
Configuration
Pure Getter Method - Configuration
Set the "Apply JavaBeans naming convention" flag by opening the settings/preferences and navigating to Editor → Inlay Hints → Other → Java → Pure Getter Method.
Example 1
Pure Getter Method - Example 1
"Apply JavaBeans naming convention" flag is set.
Example 2
Pure Getter Method - Example 2
"Apply JavaBeans naming convention" flag is not set.

Pure Setter Method

Also known as "setter", a pure mutator method only contains one statement that assigns a single parameter value to a homonymous field which must be qualified and within the class the method is defined in. The application of the standard JavaBeans naming convention on the signature's name can be enforced by selecting or deselecting a checkbox in the IDE's corresponding Inlay Hint settings menu.

Inlay hint information
Emoji 📥
Impacted identifiers Method names
Configuration
Pure Setter Method - Configuration
Set the "Apply JavaBeans naming convention" flag by opening the settings/preferences and navigating to Editor → Inlay Hints → Other → Java → Pure Setter Method.
Example 1
Pure Setter Method - Example 1
"Apply JavaBeans naming convention" flag is set.
Example 2
Pure Setter Method - Example 2
"Apply JavaBeans naming convention" flag is not set.

State Changing Method

A method changing state contains value assignments to class fields that are either stated explicitly or implicitly by invoking mutator methods.

Note that each implicitly state-changing method call can be followed recursively until reaching its original caller. If any method on the invocation path to the root invoker matches the criteria specified above, the method being currently analyzed is marked with a hint indicating its state-changing effect. Since this might be a costly operation for methods comprising many method calls, this option is turned off by default in the IDE's corresponding Inlay Hint settings menu.

Inlay hint information
Emoji 🎚️
Impacted identifiers Method names
Configuration
State Changing Method - Configuration
Set the "Follow method calls and recursively check state change" flag by opening the settings/preferences and navigating to Editor → Inlay Hints → Other → Java → State Changing Method.
Example 1
State Changing Method - Example 1
"Follow method calls and recursively check state change" flag is set.
Example 2
State Changing Method - Example 2
"Follow method calls and recursively check state change" flag is not set.

State Independent Method

A method that is independent of state does not contain any expressions that reference a class field either explicitly or implicitly through method invocations.

Note that each implicitly state-independent method call can be followed recursively until its original caller is reached. If all methods on the invocation path to the root invoker match the criteria specified above, the method being currently analyzed is marked with a hint indicating its state independence. Since this might be a costly operation for methods comprising many method calls, this option is turned off by default in the IDE's Inlay Hint settings menu.

Inlay hint information
Emoji 🧊
Impacted identifiers Method names
Configuration
State Independent Method - Configuration
Set the "Follow method calls and recursively check state independence" flag by opening the settings/preferences and navigating to Editor → Inlay Hints → Other → Java → State Independent Method.
Example 1
State Independent Method - Example 1
"Follow method calls and recursively check state independence" flag is set.
Example 2
State Independent Method - Example 2
"Follow method calls and recursively check state independence" flag is not set.

Vulnerable Dependency Usage Detection

The CodeEmoji plugin now includes a new feature to detect and highlight the usage of vulnerable dependencies within Java projects. This functionality enhances the plugin's capability to assist developers in identifying potential security risks in their code.

Inlay Types

This feature introduces three distinct types of inlays to highlight different aspects of vulnerable dependency usage:

1. Vulnerable Dependency Call

Aspect Description
Emoji 💀 (Skull)
Impacted Identifiers Method references (i.e., method calls)

This inlay specifically marks calls to methods that are part of a vulnerable dependency.

Use Case: Provides immediate, in-context information about specific vulnerable method calls, allowing developers to make informed decisions about using or replacing these calls.

Tooltip Information: Provides detailed information about the vulnerability, including:

  • The name of the vulnerable dependency
  • The scanner used to identify the vulnerability
  • The number and severity of vulnerabilities (Critical, High, Medium, Low)

Example: "OSVScanner - org.apache.commons/commons-text@1.9 has 1 critical, 1 medium vulnerability"

Vulnerable Dependency Call Example

2. Vulnerable Method

Aspect Description
Emoji ⚠️ (Warning Sign)
Impacted Identifiers Method names in signatures and references

This inlay indicates methods that directly use one or more vulnerable dependencies.

Use Case: Quickly highlights methods that directly interact with known vulnerable dependencies, allowing developers to identify potential security risks in their code at a glance.

Tooltip Information: Shows the number of vulnerable dependencies used by the method. Example: "This method is using 2 vulnerable dependencies"

Vulnerable Method Example

3. Indirect Vulnerable Method

Aspect Description
Emoji ⛔ (Stop Sign)
Impacted Identifiers Method names in signatures

This inlay identifies methods that indirectly use vulnerable dependencies through calls to other non-external methods.

Use Case: Helps developers identify potential security risks that may not be immediately apparent, as the vulnerable dependency usage is indirect. It encourages a more thorough code review and consideration of the whole dependency chain.

Tooltip Information: A simple statement indicating indirect usage of vulnerable dependencies. Example: "This method is indirectly using vulnerable dependencies"

Indirect Vulnerable Method Example

This inlay hint can be deactivated in case the user doesn't want to recursively check for vulnerable dependencies usage like in the image below.

Deactivate Recursion

Configuration

The VulnerableDependency provider allows for customization through the VulnerableDependencySettings class. Notably, the indirect vulnerable method check can be toggled on or off using the isCheckVulnerableDependencies setting.

By implementing these three inlay hints, the VulnerableDependency provider offers a comprehensive view of vulnerable dependency usage in a Java project, from direct method calls to indirect usage through other methods. This multi-layered approach enables developers to identify and address potential security risks in their codebase quickly and efficiently.

How to Extend

The codEEmoji plugin is under to the terms and conditions of the GNU General Public License version 3.0. The source code can be accessed on the GitHub platform, whereby the repository contains two distinct branches: "main" for official releases and "develop" for ongoing development activities. The software is extensively developed using the IntelliJ Platform Plugin SDK. For individuals without familiarity with the process of developing plugins for the IntelliJ IDEA IDE, it is recommended to visit the official website in order to acquire a foundational understanding of the subject. An appropriate first reference for individuals with further expertise would be the section pertaining to Inlay hints. It is noteworthy to acknowledge that the inclusion of the Inlay hints feature represents a recent addition to the IntelliJ IDEA IDE. Additionally, it is worth mentioning that the codEEmoji plugin was created utilizing numerous APIs that have been designated as @Experimental. The APIs have the potential to undergo modifications in the future, which could result in compatibility challenges. Nevertheless, the present condition of the plugin indicates that it is entirely compatible with versions 2023.1.x and 2023.2.x, provided that JDK 17 or a higher version is utilized.

As mentioned in the reference page for implementing Inlay hints in the IDE, "Inlay hints render small pieces of information directly into the editor and give developers additional code insight without disturbing the workflow. A well-known example is parameter hints that usually display the name of the function parameters as given in its declaration". Inlay hints can be of the type inline (inlays displayed in the code between code tokens) or block (inlays displayed above a code block) and must be implemented by a provider class that is registered in the plugin configuration file. All cases implemented in the codEEmoji plugin are inlay hints that extend or implement the interface InlayHintsProvider.

Providers

The codEEmoji plugin provides two abstract classes (CEProvider and CEProviderMulti) that implement the interface InlayHintsProvider. They are starting points for implementing a case for adding an inlay hint. See figure that follow.

Provider Class Diagram - Example

As can be seen in the diagram above, a class of type InlayHintProvider must implement a series of methods which will allow you to configure the inlay hint case in the IDE, allowing you to configure it in the appropriate menus for a programming language. The most important point concerns the getCollectorFor(PsiFile, Editor, S, InlayHintsSink) method. This method returns a class of type InlayHintsCollector. This class that is responsible for scanning the source code elements and execute the logic to identify the point where the addition of an inlay hint is necessary.

Collectors

Generally a class of type InlayHintProvider is linked to a class of type InlayHintCollector. At this point, the class CEProviderMulti differentiates itself. It extends the CEProvider class and allows a list of coupled collectors.

The codEEmoji provides a rich API for implementing classes of type InlayHintsCollector. The figure below displays the class diagram available for this purpose.

Collector Class Diagram - Example

The InlayHintsCollector framework interface can be implemented in the plugin by the CECollector and CECollectorMulti. The interface defines the collect(PsiElement, Editor, InlayHintsSink) method. CECollectorMulti allows you to implement this method using a list of collectors, useful for use with CEProviderMulti.

The CECollector abstract class is the main class for implementing a collector. It extends the abstract class CEInlayBuilder which contains all the methods for manipulating inlay hints. Child classes must implement processCollect(PsiElement, Editor, InlayHintsSink).

CECollector Class Diagram - Example

The class CEDynamicInlayBuilder is extending the class CEInlayBuilder and overwriting some of its methods. This is necessary to allow the dynamic creation of the inlays.

The CECollector has four main extensions: CESimpleCollector, CEProjectCollector, CEImplicitCollector and CESimpleDynamicCollector. The first is for general use and CESimpleDynamicCollector is a almost identic implementation of that, that serves to dynamically create the inlays. The other two extensions are specific cases for working with implicit annotations and specifications of projects. The following sections explore each case.

CESimpleCollector

Child classes of CESimpleCollector must implement the needsHint(H, Map) method. This method is parameterized by type of element to be analyzed and answers whether it is necessary to add an inlay hint according to the logic of the concrete child class.

The codEEmoji provides six abstract classes that directly extend CESimpleCollector that allow you to abstract the collect of elements of type Class, Method and Variable (Field, Parameter and Local Variable), in addition to elements that are referenced in the source code: Reference Class, Reference Field and Reference Method.

CESimpleCollector Class Diagram - Example

Example of use:

public class GetMethodDoesNotReturn extends CEProvider<NoSettings> {

    @Override
    public String getPreviewText() {
        return """
                public class Customer {
                    public void getName() {
                        doSomething();
                    }
                }""";
    }

    @Override
    public @NotNull InlayHintsCollector buildCollector(@NotNull Editor editor) {
        return new CEMethodCollector(editor, getKeyId(), CONFUSED) {
            @Override
            public boolean needsHint(@NotNull PsiMethod element, @NotNull Map<?, ?> externalInfo) {
                return (element.getName().startsWith("get")
                        || element.getName().startsWith("return"))
                        && Objects.equals(element.getReturnType(), PsiTypes.voidType());
            }
        };
    }
}

For implementations of reference type elements, the plugin already provides abstract classes to work with references to modifiers in classes, methods, fields, and interface methods.

CESimpleCollector Class Diagram - Example

Example of use:

public class ShowingModifiers extends CEProviderMulti<ShowingModifiersSettings> {

    //source code omitted...

    @Override
    public @NotNull List<InlayHintsCollector> buildCollectors(@NotNull Editor editor) {
        List<InlayHintsCollector> list = new ArrayList<>();
        //fields
        list.addAll(
                Arrays.asList(
                        new CEModifierFieldCollector(editor, getKeyId(), PUBLIC_SYMBOL, PUBLIC, getSettings().query(PUBLIC_FIELD)),
                        new CEModifierFieldCollector(editor, getKeyId(), DEFAULT_SYMBOL, DEFAULT, getSettings().query(DEFAULT_FIELD)),
                        new CEModifierFieldCollector(editor, getKeyId(), FINAL_VAR_SYMBOL, FINAL, getSettings().query(FINAL_FIELD)),
                        new CEModifierFieldCollector(editor, getKeyId(), PROTECTED_SYMBOL, PROTECTED, getSettings().query(PROTECTED_FIELD)),
                        new CEModifierFieldCollector(editor, getKeyId(), PRIVATE_SYMBOL, PRIVATE, getSettings().query(PRIVATE_FIELD)),
                        new CEModifierFieldCollector(editor, getKeyId(), STATIC_SYMBOL, STATIC, getSettings().query(STATIC_FIELD)),
                        new CEModifierFieldCollector(editor, getKeyId(), VOLATILE_SYMBOL, VOLATILE, getSettings().query(VOLATILE_FIELD)),
                        new CEModifierFieldCollector(editor, getKeyId(), TRANSIENT_SYMBOL, TRANSIENT, getSettings().query(TRANSIENT_FIELD))
                )
        );

        //source code omitted...

        return list;
    }
}

External Analyzers

The plugin ensures that before invoking the needsHint(H, Map) method, the element under collect analysis is sent to everyone analyzers with external services using processExternalInfo(H) method. To do this, a Map is passed to fill in the respective information for each service using a CEExternalAnalyzer singleton and the list of implementations of CEEExternalService interface. This way, in the concrete child class, the needsHint(H, Map) method receives a Map with information that can subsidize the addition or not of an inlay hint.

CEExternalAnalyzer Class Diagram - Example

CEProjectCollector

CEProjectCollector provides ways to work with a specific case of collector. It allows you to collect elements configurable according to the codeemoji.json configuration file directly in the user's project. The plugin already provides classes for collecting elements of type Class, Method and Variable. The diagram below shows these collectors and displays the available interfaces.

CEExternalAnalyzer Class Diagram - Example

Example of use:

public class ShowingSpecifics extends CEProviderMulti<ShowingSpecificsSettings> {

    //source code omitted...

    @Override
    public @NotNull List<InlayHintsCollector> buildCollectors(@NotNull Editor editor) {
        List<InlayHintsCollector> list = new ArrayList<>();

        list.add(new CEProjectClassCollector(editor, getKeyId()));
        list.add(new CEProjectMethodCollector(editor, getKeyId()));
        list.add(new CEProjectVariableCollector(editor, FIELD, getKeyId()));
        list.add(new CEProjectVariableCollector(editor, PARAMETER, getKeyId()));
        list.add(new CEProjectVariableCollector(editor, LOCALVARIABLE, getKeyId()));

        return list;
    }

    @Override
    public @NotNull ImmediateConfigurable createConfigurable(@NotNull ShowingSpecificsSettings settings) {
        return new ShowingSpecificsConfigurable(settings);
    }

}

CEImplictCollector

CEImplicitCollector is also a specific type of collector in the plugin. It allows you to detect the need for implicit annotations hints to be added via block-type inlay hint. It also allows you to detect implicit annotation attributes as well as their respective implicit values.

The plugin already provides implementation for several annotations of the JPA and Spring, being fully extensible to other frameworks. In the diagram below, an example of JPA with @Entity and @Column. CEJPAEntityCollector defines a collector to work with the main annotation @Entity. The collector has a list of classes that implement the CEImplicit interface. This way, each item in this list is invoked to investigate whether to process an inlay hint.

CEExternalAnalyzer Class Diagram - Example

Example of use:

public class ImplicitAnnotations extends CEProviderMulti<ImplicitAnnotationsSettings> {

    //source code omitted...

    @Override
    public @NotNull List<InlayHintsCollector> buildCollectors(@NotNull Editor editor) {
        final int codePoint = 0x1F4AD;
        String keyId = getKeyId();
        return new ArrayList<>(
                Arrays.asList(
                        new CEJPAEntityCollector(editor, keyId, codePoint, "javax.persistence"),
                        new CEJPAEntityCollector(editor, keyId, codePoint, "jakarta.persistence"),
                        new CEJPAEmbeddableCollector(editor, keyId, codePoint, "javax.persistence"),
                        new CEJPAEmbeddableCollector(editor, keyId, codePoint, "jakarta.persistence"),
                        new CESpringConfigurationCollector(editor, keyId, codePoint),
                        new CESpringControllerCollector(editor, keyId, codePoint),
                        new CESpringRestControllerCollector(editor, keyId, codePoint)
                ));
    }

    //source code omitted...
}

CESimpleDynamicCollector

The CESimpleDynamicCollector is an implementation of the CECollector that allows for the dynamic creation of inlays. Its implementation is nearly identical to that of CESimpleCollector, with a key difference in the constructor:

  • The constructor only receives the editor as a parameter, as it doesn't need to create the inlay when the collector is defined.

New Dynamic Collector

The primary changes that enable dynamic inlay creation are in the processCollect function implementation in the classes extending CESimpleDynamicCollector. As shown in the figure below, the needsHint method in these classes returns the inlay to be shown or null if no inlay should be displayed, rather than a boolean value as in other collectors.

Dynamic Process Collect Example of processCollect implementation in class CEDynamicMethodCollector extending CESimpleDynamicCollector

This dynamic approach allows for more flexible and context-sensitive inlay creation, as the decision to display an inlay and its content can be determined at runtime based on the current state of the code being analyzed. This new structure provides greater flexibility in inlay generation, allowing for more complex and context-aware code augmentation scenarios.

Internationalization

The plugin is fully ready for internationalization. The CEBundle.properties bundle is provided. All strings for tooltips, settings, warnings, information and exceptions can be internationalized centrally. At the moment, all these messages are in the English language. To extend it to another language, simply create a file named with CEBundle_XX.properties, where XX stands for the language acronym. The IDE will automatically detect the language used and carry out the appropriate configuration.

Acknowledgements

This work was supported by the Free University of Bozen-Bolzano - UNIBZ.

References

Arnaoudova, Venera, Massimiliano Di Penta, and Giuliano Antoniol. "Linguistic antipatterns: What they are and how mainers perceive them." Empirical Software Engineering 21 (2016): 104-158.

Michele Lanza and Radu Marinescu. "Object-Oriented Metrics in Practice". Springer Berlin, Heidelberg, Edition 1 (2006): Table 2.1.

Arthur H. Watson and Thomas J. McCabe. "Structured Testing: A Testing Methodology Using the Cyclomatic Complexity Metric." NIST Special Publication (SP) (1996).

About

codeEEmoji is a Java programming plugin created for Intellij Idea. In the context of code augmentation, the plugin provides additional sets of inlay hints. The new inlay hints assist the developer in an original approach by using emojis.

Topics

Resources

License

Stars

Watchers

Forks

Languages