Basics of working with structural search in IntelliJ IDEA 9, 10 or 11

From IntelliJ-Wiki

Jump to: navigation, search

This tutorial offers a set of exercises intended to help you get started with structural search in IntelliJ IDEA.

First, you will:

Then, you will perform a number of search exercises and learn how to:

Contents

Additional sources of information

You can read more about the structural search in:

Before you start

To be able to perform the exercises discussed in this tutorial, make sure that the following software is installed on your computer:

  • IntelliJ IDEA Ultimate Edition, version 9, 10 or 11.
  • Java Development Kit (JDK), version 1.5 or later. You can download the necessary version of Oracle JDK from the Java SE Downloads page.

Understanding structural search concepts

Structural search is a search for language constructs in your source code (Java, html, xml, etc.).

You specify what you want to find using search templates. Templates are valid language constructs containing fixed text and variables.

A typical example of the search template is class $Class$ {}. In this template, class and {} is the fixed text. $Class$ is a variable which, in this template, represents the name of the class. (Variables in search templates are text fragments enclosed between the dollar sings $.)

To make your search more precise, you can define various types of constraints for any variable within a template. The most popular types of constraints are text constraints and occurrence count constraints. The text constraints define the (text) patterns that the value of a variable must match. The occurrence count constraints specify how many times similar syntactic units represented by a variable may occur in the source code.

There may be one or more search targets associated with a template. The search target is either the whole template, or one or more variables within the template. The targets represent the part that, within the template, is of most interest to you.

As a rule, the code formatting in search templates and source code does not matter. Sometimes, when matching a template against the source code, certain semantic aspects are also taken into account.

For more on the structural search and search templates, see IntelliJ IDEA Help.

Preparing for the search

To demonstrate the features of the structural search we need something to search within. We need a project and at least one Java class. So to prepare for the search:

1. Create a project from scratch. When doing so, select to create a Java module. For additional instructions, see "Creating a project". We will create the project called SSRDemo located in C:\IdeaProjects\SSRDemo.

2. In the src directory (the default location for Java source files), create a Java class called MetersToInchesConverter. For additional instructions, refer to "Creating a new Java class".

3. Copy the source code of MetersToInchesConverter into the class file you have created at the previous step and save the file. The code and corresponding instructions are provided in "Copying the source code".

After completing these steps you will be ready to start exercising the structural search.

Creating a project

To create a project with a Java module:

1. Select File | New Project.

2. Make sure that Create project from scratch is selected on the first page of the New Project wizard.

File:001_new_project_create_from_scratch.png

Click Next.

3. On the next page of the wizard, specify the name of your new project (for example, SSRDemo (1)).

If necessary, change the default location of the project files (in the Project files location field (2)).

Make sure that the Create module check box is selected (3), and also Java Module is selected under Select type (4). Don’t change any other of the default module settings (the name, content root and the location of the module file).

File:002_new_project_name_and_location.png

Click Next.

4. On the next page of the wizard, choose Create source directory (1) and accept the default name src (2).

File:003_new_project_source_directory.png

Click Next.

5. If you have never specified a JDK in your copy of IntelliJ IDEA, you’ll be asked to do so on the next page of the wizard. (If the page discussed below is not shown, you already have a JSDK configured. In this case, proceed to completing the wizard.)

Click Configure.

File:004_new_project_select_jdk.png

In the Select Home Directory for JSDK dialog, specify the installation directory of the desired JDK (1) and click OK (2).

File:005_new_project_select_jdk_select_path.png

Click Next.

6. On the next page of the wizard (where you are asked to select the technologies to be supported), just click Finish to complete the wizard.

Wait while IntelliJ IDEA is creating the necessary project structures. When this process is complete, you can see the structure of your new project in the Project tool window.

Creating a new Java class

To create a new Java class:

1. In the Project tool window, right-click the src folder (1), click New (2), and then click Java Class (3).

File:007_create_java_class.png

2. In the Create New Class dialog, type the name of the class in the Name field (for example, MetersToInchesConverter; this name reflects the functionality that the class will implement) and click OK.

File:008_create_java_class_specify_name.png

As a result, the class with the specified name is created and opened in the editor.

Copying the source code

1. In the file MetersToInchesConverter.java, replace

public class MetersToInchesConverter {
}

with the following:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class MetersToInchesConverter {

    static boolean processRepeatConversion (String userInput) {
        boolean repeatConversion = false;
        if (((userInput.equals("y")) || (userInput.equals("Y")))) {
            repeatConversion = true;
        }
        return repeatConversion;
    }

    static String[] convertMetersToInches (String metersToConvertString) {
        String[] conversionResult = new String[2];
        double conversionFactor = 39.37;
        try {
            double metersToConvertDouble = Double.parseDouble(metersToConvertString);
            double inchesDouble = metersToConvertDouble*conversionFactor;
            String inchesString = Double.toString(inchesDouble);
            conversionResult[0] = "CONVERSION RESULT: " + metersToConvertString + " m = " + inchesString + " inches";
            conversionResult[1] = "Do you want to convert another number?";
        } catch (NumberFormatException nfe) {
            if (nfe.getMessage().equals("empty String")) {
                conversionResult[0] = "CONVERSION FAILED: " + "You forgot to specify the number of meters.";
            } else {
                conversionResult[0] = "CONVERSION FAILED: " + "\"" + metersToConvertString + "\" is not a number.";
            }
            conversionResult[1] = "Do you want to try once more?";
        }
        return conversionResult;
    }

    public static void main (String[] args) throws IOException {
        String s;
        System.out.println("METERS TO INCHES CONVERTER WELCOMES YOU!");
        do {
            BufferedReader buff = new BufferedReader(
            new InputStreamReader(System.in));
            System.out.print("Enter the number of meters (m) to convert into inches: ");
            System.out.flush();
            s = buff.readLine();
            String result[] = convertMetersToInches (s);
            System.out.println(result[0]);
            System.out.print(result[1] + " (Type \"y\" for \"yes\", any other symbol for \"no\".): ");
            System.out.flush();
            s = buff.readLine();
        } while (processRepeatConversion(s));
        System.out.println("THANKS FOR USING OUR CONVERTER. BYE!");
    }

}

2. Press CTRL+S to save the changes.

Take a quick look at the code to see which language constructs you can potentially search for. Then close the file by clicking File:000_icon_close.png on the editor tab or pressing CTRL+F4.

File:010_close_java_file.png

Searching for classes. Learning the basic features of the UI

In this section, we show how to access the Structural Search dialog and briefly discuss its layout and main features. Then, we perform the most basic search (the search for classes) using one of the predefined templates (sections "Specifying a search template" and "Performing the search") and discuss the results (sections "Exploring the search results" and "How access modifiers affect the search for classes"). We also show how to jump to the source code for a found code fragment and repeat the search for the refined conditions.

Accessing the Structural Search dialog

The Structural Search dialog provides an access point to structural search in IntelliJ IDEA. In this dialog you define what you want to find and where, and also specify various search options such as case sensitivity, recursion and the like.

To open the Structural Search dialog, select Edit | Find | Search Structurally. (Alternatively, press CTRL+SHIFT+S.)

File:011_select_to_search_structurally.png

Overview of the Structural Search dialog

Prior to performing our first structural search let’s have a quick look at the Structural Search dialog (for a more detailed discussion of this dialog, refer to IntelliJ IDEA Help).

When you first open the dialog, it looks something like this:

File:011a_structural_search_init_state.png

  • The area under Search template is where you specify the search template. A bit later we will show how.
  • The Recursive matching and Case sensitive options are initially selected. However, IntelliJ IDEA may automatically change these settings as soon as you select a search template. During all our search exercises, both these options will stay deselected.
  • The File type option, among other things, defines the language context for the template being used. That is, the template is validated using the rules of the language selected in the File type list. If java is selected, the template has to be a syntactically valid Java construct. The same applies to other file types (html, xml, etc.).
  • Scope. In this tutorial we will search in the broadest scope possible (that is, in all project files). Our project is very small so we are not going to anyhow constrain the search scope.
  • Status. Unless the search template is a valid language construct, you’ll see the warning This pattern is malformed and won’t be able to perform the search.

Specifying a search template

Our first search will be a very basic one. We will search for Java classes existing in our project.

The easiest and most effective way to specify a search template is to use one of the predefined templates. As far as Java is concerned, there’s a lot of predefined templates and it’s very unlikely that you need more.

To use one of the predefined templates (in this exercise we will use the predefined template that finds all Java classes), do the following:

1. Click Copy existing template.

File:012_structural_search_copy_template.png

The Existing Templates dialog is displayed. A categorized list of existing templates is shown in the left-hand part.

2. In the list of the templates, under class-based, select classes.

The selected template is shown in the right-hand part of the dialog under Template preview.

Note the template structure. There are two distinct parts in the template, that is, a fixed and a variable part. The fixed (constant) part is represented by the key word class and the curly brackets {}. The variable part is $Class$. In this template, $Class$ is a variable that represents the name of the class. (Variables in search templates are text fragments enclosed between the dollar sings $.)

File:013_existing_templates_classes_selected.png

3. Click OK in the Existing Templates dialog.

You are back to the Structural Search dialog. Note that the Recursive matching and Case sensitive options have automatically been deselected. IntelliJ IDEA has provided the most appropriate settings for the chosen template.

Performing the search

Note the template status in the bottom-left corner of the Structural Search dialog. The absence of a warning means that there’s nothing wrong with the template. The template is a syntactically valid Java construct. So all you have to do to perform the search is to click File:000_button_find.png.

File:014_structural_search_search_for_class.png

The Find tool window is displayed showing the search results.

Exploring the search results

Shown in the Find window are the search template used (under Targets) and the search results (under Found usages).

File:015_find_window_initial_state.png

A found usage, that is, a code fragment satisfying the search conditions, is represented by one line of code (public class MetersToInchesConverter {). In addition, the corresponding file name (MetersToInchesConverter) and the module name (SSRDemo) are shown.

The numbers in brackets ((12,14)) show where in the corresponding file the found usage occurs. (The first of the numbers is the line number; the second is the character number within this line.)

Additional details about the found code fragment are available in the Preview pane. If this pane is not currently shown, click the Preview Usages icon File:000_icon_preview_usages.png on the toolbar of the Find window. (In the same way you can also hide this pane.)

File:016_activate_preview_usages_if_not_yet.png

The Preview pane shows the corresponding code fragment in “broader context”. Normally, the first line of the code fragment is highlighted yellow. Also, what is called the search target, is highlighted violet. In this case, this is the class name MetersToInchesConverter.

File:016a_find_window_preview_other_usage.png

To move up and down in the Find window, you can use the UP ARROW and the DOWN ARROW keys. (Try this.)

Jumping to the source code for the current usage

In cases when you want to work with the found code fragment in the editor, you can jump to the source code right from the Find tool window.

Double-click (12,14) public class MetersToInchesConverter { in the Find window.

As a result the file MetersToInchesConverter.java is opened in the editor and the cursor is placed in front of the class name (MetersToInchesConverter). Note that this position corresponds to the beginning of the fragment highlighted violet in the Preview pane.

File:017_code_in_editor.png

You can achieve the same result using other methods (close the file MetersToInchesConverter.java and try both of these methods):

  • Select the usage of interest and press F4
  • Right-click the usage and click Jump to Source

File:018_jump_to_source.png

How access modifiers affect the search for classes

You may have not noticed, but access modifiers in the search for classes do not matter unless specified explicitly in the template. (The same applies to fields and methods.) To check that this is the case, perform the searches for the following two templates:

  • public class $Class$ {}. As before, you will find the class MetersToInchesConverter.
  • private class $Class$ {}. You won’t find anything.

See the next section for the basic outline of the procedure to be used.

Refining the search conditions

Situations are possible when you don’t find what you wanted in one go. In such cases you will probably slightly change the search conditions and repeat the search. Here are the instructions for this procedure:

1. In the bottom-left corner of the Find window, click Edit Query.

File:020_edit_query.png

2. In the Structural Search dialog, change the search conditions (for example, modify the template, or other settings) and click File:000_button_find.png.

Later in this tutorial, you will use this procedure many times.

Searching for methods. Working with search targets and text constraints

In this section we perform a more advanced search, the search for methods. We show how search targets and text constraints for variables affect the results (sections "Changing the search target", "Specifying a text constraint for a variable", "Inverting a text constraint for a variable" and "Changing the text constraint for a variable").

Performing an initial search

Now we are going to search for methods. As before, we’ll choose an appropriate predefined template and use it as-is:

1. In the Find tool window, click Edit Query.

2. In the Structural Search dialog, click Copy existing template.

File:021_copy_existing_template.png

3. In the Existing Templates dialog, under class-based, click methods of the class, and then click OK.

File:022_templates_methods.png

4. In the Structural Search dialog, click File:000_button_find.png.

The search results are shown in the Find tool window. All three methods defined in the MetersToInchesConverter class are found.

Note that now the names of the methods are highlighted in the Preview pane.

File:004SearchResultForMethodsE1.png

Also note that when you jump to the source code, the cursor is positioned right in front of the method names.

File:004SearchResultForMethodsInEditorE1.png

In a minute, we will change the search target and see what changes. Before that, however, let's learn a bit more about navigation.

Jumping to the source code for the next or previous usage

In the Find window, you can move onto the next or previous of the found usages and jump to the source code for that usage at the same time. To do that, use the Next Occurrence File:000_icon_next_occurence.png and the Previous Occurrence File:000_icon_previous_occurence.png icons on the toolbar.

File:NextPreviousIconsOnToolbar.png

The keyboard shortcuts for these functions are CTRL+ALT+DOWN ARROW and CTRL+ALT+UP ARROW respectively.

Let us see how this works.

While static String[] convertMetersToInches (String metersToConvertString) { is selected in the Find tool window, click Next Occurrence File:000_icon_next_occurence.png. (Alternatively, press CTRL+ALT+DOWN ARROW.)

As a result:

  • The next of the found usages is selected in the Find tool window (public static void main (String[] args) throws IOException {)
  • The declaration of the main method is shown in the Preview pane.
  • The file MetersToInchesConverter.java opens in the editor and the declaration of the main method is shown there.

Note that the Find tool window still stays in focus. (Compare with the jump to source function which always brings the editor in focus.) Now to check that the next/previous occurrence function leaves the focus where it previously was: click anywhere in the source code (in the editor) and press CTRL+ALT+UP ARROW or CTRL+ALT+DOWN ARROW. Note that the focus stays in the editor.

Changing the search target

To change the search target for the current search template:

1. In the Find tool window, click Edit Query.

2. In the Structural Search dialog, click Edit variables.

File:023_structural_search_edit_vars.png

3. In the Edit Variables dialog, under Variables, select MethodName (1). Note that the check box next to This variable is target of the search is currently selected. Currently, the template variable MethodName is the search target. This is why the method names (rather than anything else) were highlighted in the Preview pane after the previous search.

Deselect this check box (2).

File:024_select_name_deselect_target.png

Now we are going to make the variable ReturnType the search target. Click ReturnType (1) and select the check box next to This variable is target of the search (2).

File:025_select_type_select_target.png

Click OK in the Edit Variables dialog.

4. In the Structural Search dialog, click File:000_button_find.png.

As before, the three methods are found. Note, however, that now the return type is highlighted for each of the methods in the Preview pane.

File:026_same_result_different_view.png

If you jump to the source code, the cursor is positioned in front of the method return type rather than its name.

File:005DiffTargetInEditorE1.png

Now let’s see how text constraints for variables work.

Specifying a text constraint for a variable

In this section we’ll show how to change the search settings so that only the methods that return the String type are found. To do that, we will specify the appropriate text constraint for the variable ReturnType:

1. In the Find tool window, click Edit Query.

2. In the Structural Search dialog, click Edit variables.

File:027_edit_vars.png

3. In the Edit Variables dialog, select ReturnType (1). In the Text/regexp field, type string.* (2).

This pattern specifies a text fragment in which string is followed by any number of any characters. (The dot (.) means any character; the asterisk (*) stands for any number including zero.)

File:028_methods_return_string.png

Click OK.

4. In the Structural Search dialog, click File:000_button_find.png.

Look at the result in the Find window. Note that now only one method (ConvertMetersToInches) is found. This is fine because ConvertMetersToInches is the only method in our project whose return type is String.

File:029_methods_return_string_result.png

Now let’s search for the methods whose return types are not String.

Inverting a text constraint for a variable

In the previous exercise we constrained the ReturnType variable so that only the methods with the return type String are found. To find the methods that return anything other than String we will logically negate, or, in other words, invert the text constraint for the ReturnType variable:

1. In the Find window, click Edit Query.

2. In the Structural Search dialog, click Edit variables.

3. In the Edit Variables dialog, select ReturnType (1), and select the Invert condition check box (2).

As already mentioned, the Invert condition option is equivalent to logical negation. So we are going to search for the return types that don't match the pattern string.*.

File:030_methods_return_not_string.png

Click OK.

4. In the Structural Search dialog, click File:000_button_find.png.

Note that now two methods are found, and none of these methods returns String: the main method does not return any value, and the return type of processRepeatConversion is boolean.

File:031_methods_return_not_string_result.png

Now to complete the discussion of the text constraints and also for exercising, let’s search for the methods that return an array.

Changing the text constraint for a variable

To find the methods that return an array, we will appropriately redefine the text constraint for the ReturnType variable:

1. In the Find window, click Edit Query.

2. In the Structural Search dialog, click Edit variables.

3. In the Edit Variables dialog, select ReturnType (1) and clear the Invert condition check box (2).

In the Text/regexp field, type .*\[\] (3). This pattern defines a string in which any number of any characters is followed by []. (The meaning of .* has been explained earlier. The opening and the closing square brackets ([]) in the text constraints both have special meanings. To be treated literally, the special meanings of the square brackets have to be cancelled, or escaped by means of the backslashes (\).)

File:032_methods_return_array.png

Click OK.

4. In the Structural Search dialog, click File:000_button_find.png.

Note that one method is found, the convertMetersToInches. This is the only method in our project that returns an array.

File:033_methods_return_array_result.png

Searching for if-then-else. Working with the occurrence count settings

In this section we search for if-then-else statements and show how the occurrence count settings affect the search results.

Performing an initial search for if-then-else

Let us start with the predefined template and see what search results it produces:

1. In the Find tool window, click Edit Query.

2. In the Structural Search dialog, click Copy existing template.

File:034_copy_existing_template.png

3. In the Existing Templates dialog, under operators, selects if’s and click OK.

File:035_template_for_if_else.png

4. In the Structural Search dialog, click File:000_button_find.png.

Note that two if-then statements are found. The first of the statements contains the else block while the other doesn’t.

File:036_if_with_else.png

File:037_if_without_else.png

Let us find out why this is so.

Changing the occurrence count settings

The previous search result has to do with how the occurrence count parameters for the variable ElseStatement are set. Now we going to show this and also change the settings to get rid of the if-then statements without the else block:

1. In the Find tool window, click Edit Query.

2. In the Structural Search dialog, click Edit variables.

File:038_edit_variables.png

3. In the Edit Variables dialog, select ElseStatement. Note the settings for the occurrence count.

These settings currently specify that the else block containing from 0 to an unlimited number of else-then statements satisfy the search conditions.

File:039_occurence_count.png

By default, the minimum occurrence count for ElseStatement is zero. This means that the if-then-else statements in which there is the else block but no else-then statements (for example, else {}) satisfy the search conditions. On the other hand, the absence of the else-then statements is semantically equivalent to the absence of the whole else block. That is why the if-then-else statement without the else block was also found in the previous search.

Let’s set the minimum count to 1. By doing so we require the else block to contain at least one else-then statement:

Type 1 in the Minimum count field and click OK.

File:040_else_min_1.png

4. In the Structural Search dialog, click File:000_button_find.png.

Note that now only the if-then-else statement with the else block is found.

File:041_only_if_with_else_found.png

To complete our exercises let us show how to modify and save a search template.

Modifying and saving a search template

In this section we modify the if-then-else template so that it finds only the if-then statements without the else block. Then we save the modified template and show where you can find it.

Modifying a search template

To modify a search template:

1. In the Find window, click Edit Query.

2. In the Structural Search dialog, under Search template, delete the part corresponding to the else block:

else {
  $ElseStatement$;
}

Finally, the template should look as shown on the following picture:

File:042_template_for_if_without_else.png

3. Click File:000_button_find.png to see what can be found using this template.

Note that only the if-then statement without the else block is found.

File:043_only_if_without_else_found.png

Let’s save this template to be able to use it in the future.

Saving a search template

To save the template:

1. In the Find tool window, click Edit Query.

2. In the Structural Search dialog, click Save template.

File:044_saving_new_template.png

3. In the Save template dialog, under Template name, type the name for your new template (for example, if without else). Then click OK.

File:045_saving_new_template_name.png

4. Now to see this new template in the list of existing templates, click Copy existing template.

File:046_copy_existing_template.png

The Existing Templates dialog opens. Note that the template you have just saved (if without else) appears in the user defined category.

File:047_new_template_in_list.png

Note: To be able to find the if-then statements without the else block, we, in fact, didn't have to modify the predefined if-then-else template. We could have just set both the minimum and the maximum occurrence counts for the variable ElseStatement to zero. You can now check that as an additional exercise.

Personal tools