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
- Cases of Naming Violation
- Short Descriptive Name
- Getter More Than Accessor
- Is Returns More Than a Boolean
- Setter Method Returns
- Expecting But Not Getting a Single Instance
- Validation Method Does Not Confirm
- Getter Does Not Return
- Not Answered Question
- Transform Method Does Not Return
- Expecting But Not Getting a Collection
- Says One But Contains Many
- Name Suggests Boolean By Type Does Not
- Says Many But Contains One
- Name Contains Only Special Characters
- Cases of Showing Modifiers
- Cases of Showing Specifics of Projects
- Cases of Showing Implicit Annotations
- Cases of Structural Analysis
- External Services API
- How to Extend
- Acknowledgements
- References
- IntelliJ IDEA 2023.* (Ultimate, Community or Educational)
- JDK 17 (Eclipse Temurin - as a suggestion)
JetBrains Marketplace - codEEmoji
- Download the latest release zip file available from Releases.
- 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**".
- Restart IDE.
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".
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:
- Navigate to "File>Settings>Plugins>codEEmoji Settings".
- Deactivate the option as shown in the figure below:
The vulnerability scanner allows users to choose between two different scanners for inspecting project dependencies:
- Default Scanner: OSV.dev scanner (Documentation: OSV.dev)
- 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:
-
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.
-
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.
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
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
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
A setter method that has a return type other than void. Adapted from Arnaoudova et al.(2016).
Impacted identifiers: Method Names
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
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
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
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
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
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
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
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
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
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
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
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:
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.
Here's an example of usage from a code snipped:
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.
Here's an example of usage with JPA from a code snipped:
Here's an examples of usage with Spring from a code snipped:
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.
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.
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 |
---|
Set custom thresholds by opening the settings/preferences and navigating to: Editor → Inlay Hints → Other → Java → High Cyclomatic Complexity 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 |
---|
Set a custom threshold by opening the settings/preferences and navigating to Editor → Inlay Hints → Other → Java → 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. |
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 |
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. |
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 |
---|
Set a custom threshold by opening the settings/preferences and navigating to Editor → Inlay Hints → Other → Java → 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. |
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.
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 |
Example 1 |
---|
"Follow method calls and recursively check externality" flag is checked. |
Example 2 |
---|
"Follow method calls and recursively check externality" flag is not set. |
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 |
---|
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 |
---|
"Apply JavaBeans naming convention" flag is set. |
Example 2 |
---|
"Apply JavaBeans naming convention" flag is not set. |
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 |
---|
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 |
---|
"Apply JavaBeans naming convention" flag is set. |
Example 2 |
---|
"Apply JavaBeans naming convention" flag is not set. |
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 |
---|
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 |
---|
"Follow method calls and recursively check state change" flag is set. |
Example 2 |
---|
"Follow method calls and recursively check state change" flag is not set. |
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 |
Example 1 |
---|
"Follow method calls and recursively check state independence" flag is set. |
Example 2 |
---|
"Follow method calls and recursively check state independence" flag is not set. |
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.
This feature introduces three distinct types of inlays to highlight different aspects of vulnerable dependency usage:
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"
Aspect | Description |
---|---|
Emoji | |
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"
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"
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.
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.
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.
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.
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.
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.
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).
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.
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.
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.
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;
}
}
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.
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.
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);
}
}
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.
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...
}
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.
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.
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.
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.
This work was supported by the Free University of Bozen-Bolzano - UNIBZ.
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).