CDT Code Completion Design Proposal
Place a quick description of the design area here
Author : Hoda Amer
Revision Date : 07/11/2003 - Version: 0.1.0
Change History : 0.1.0 - Document Creation

Table of Contents

1. Introduction
1.1 Overview
2. Requirements
3. JDT Design Overview
4. CDT Design Overview
5. References


1. Introduction

In JDT, Code Assist is a broad term. It includes Code Selection and Code Completion. Code Selection is concerned with finding context information, such as mapping the current selection in the editor to a possible model element, while Code Completion is concerned with finding possible completions at the current cursor position when a certain combination of keys is pressed. This document proposes a design to implement Code Completion in CDT, not including the template completions.

1.1 Overview

CDT already has some code assist available in the current release. However, its capabilities are limited and it is highly dependent on CTags. To help enhance code assist in CDT, we are proposing a design similar to the one in JDT that depends on parsing the current document and trying to predict the logical completions at the cursor position. At first we state the requirements of this feature and the limitations we have. Then we describes how Code Completion is implemented in JDT. Finally, we introduce the proposed high level design.

2. Requirements

The requirements for code completion in CDT is to find proposals to complete the code at the current cursor position whenever a certain combination of keys is pressed (for example CTRL+SPACE). Each proposal has an associated relevance number.

Due to the complexity of the C/C++ languages and due to time limitations, code completion will be done in two phases:

2.1 Phase 1

Since CTags will retire for the upcoming release 1.2, code completions will be changed to depend on the new Indexer. Code completion should be able to provide the same functionality it is providing today.

2.2 Phase 2

All possible cases for code completion will be supported. Just like in the JDT, it will depend on parsing the current document and trying to predict the type of node to complete. User preferences for code completion will be available as well.

Examples where code completion is requested:

Single Name Reference

int aVar;

void foo(){

    a(CTRL+SPACE)

}

Basic Qualified Name Reference

Class D{

    int aVar;

};

void foo(){

    D d;

    d.a(CTRL+SPACE)

}

Complex Qualified Name Reference

void foo(){

    ((D*)func())->a(CTRL+SPACE)

}

 

3. JDT Design Overview

Code assist in JDT is used for two purposes:

  1. Context Information: If some source is selected in the editor, try to find the Java model element that corresponds to it.
  2. Completion Proposals: If some special key combination is pressed, try to find completion proposals that would fit after the current cursor position.

This document describes the completion proposals part of code assist only (not including template completions).

The request to for code assist arrives through jface to the editor’s source viewer. The JavaSourceViewerConfiguration class assigns one or mode completion processors. It creates the JavaCompletionProcessor and forwards the request to it. The JavaCompletionProcessor finds the current document’s working copy and forwards the request to it in turn. It also created a result collector to receive all proposals. The request includes the current cursor position.

The working copy uses the CompletionEngine for code completion. The CompletionEngine class is the entry point for code completion. Completion proposals are computed and sent to an ICompletionRequestor. Each proposal has an associated relevance; a positive integer that may be used to compare this proposal to other suggested proposals. The relevance of a code completion candidate can be affected by the expected type of the expression, as it relates to the types in the surrounding code, such as variable types, cast types, return types, etc.  The presence of an expected prefix or suffix in a completion also affects its relevance.

When asked to complete on a certain compilation unit, the completion engine parses the compilation unit without going into function bodies (using CompletionParser.dietParse()). The Completion Parser, a subclass of Parser, estimates the AST node being completed. The AST node being completed could be one of the following:

CompletionOnArgumentName, CompletionOnClassLiteralAccess, CompletionOnClassReference,  CompletionOnExceptionReference,  CompletionOnExplicitConstructorCall,  CompletionOnFieldName, CompletionOnFieldType, CompletionOnImportReference, CompletionOnInterfaceReference, CompletionOnKeyword, CompletionOnLocalName, CompletionOnMemberAccess, CompletionOnMessageSend, CompletionOnMethodName, CompletionOnMethodReturnType, CompletionOnPackageReference, CompletionOnQualifiedAllocationExpression, CompletionOnQualifiedClassReference, CompletionOnQualifiedExceptionReference, CompletionOnQualifiedInterfaceReference, CompletionOnQualifiedNameReference, CompletionOnQualifiedTypeReference, CompletionOnSingleNameReference, CompletionOnSingleTypeReference.

Some of the above nodes could be found even when parsing without going into function bodies (performing a diet parse). For example, CompletionOnPackageReference and CompletionOnImportReference could occur as a result of a diet parse. The completion engine checks these possibilities one by one. If it finds that the compilation unit's package is an instance of CompletionOnPackageReference, it searches for the possibilities of the enclosing package. Similarly, if it finds that the completion is required for an import (i.e. one of the imports is an AST node of type CompletionOnImportReference), it searches for possibilities on that particular import. Finally, if non of these possibilities is true, it proceeds and parses the method in which completion is required.

Right before parsing the method in which completion is required, the Completion Engine builds the type bindings. This means it converts the types (classes) in the parsed compilation unit from AST nodes into scopes and bindings. This will help determine the scope of each type and its hierarchy and resolve any relationship it might have with an interface or an inner class. For example, using a class binding, you could get its super class and all its methods, etc...

Using the given position and information about the beginning and end of each method binding in the parsed compilation unit, the Completion engine determines the method in which completion is required and parses its body as a block of statements without balancing brackets. Here the parser estimates the completion node and determines its type. The engine checks possibilities one by one. Assuming that it found out that the completion node is of type  CompletionOnSingleNameReference, it does the following:

    - Find all variables and methods that would fit the given criteria ( visibility, prefix, etc...) by looping in two dimensions: one checking the scope and the other checking the hierarchy. The algorithm does the following:

            1. Get the current scope

            2. If it is a Type scope, then find all possible variables and methods,

            3. filter the ones meeting the given criteria and calculate a relevance for each proposal.

            4. Check for any interface implemented by that type and find their methods as well

            5. Get the parent class

            6. Loop for all parent classes and perform the same checks until you reach no parents (the object class)

            7. Loop for all enclosing scopes until you reach the scope of the compilation unit.

For each possible AST completion node, there is an associated algorithm that tries to find relevant matches. The search engine is sometimes used to find occurrences of some elements; for example, finding all methods that start with "a" in a particular class and its hierarchy.

Finally, all results are sent to the ICompletionRequestor and a sorting is performed on them. They are automatically displayed in the appropriate window.

4. CDT Design Overview

This section discusses the high level design for Code Completion (Phase 2).

As described in the previous section, code completion in JDT is composed mainly of two parts: the Completion Parser, and the Completion Engine. The parser attempts to predict the AST node being completed. The Completion Engine generates the proposals by checking the possibilities one by one and performing the relevant searches accordingly. It also calculates the relevance associated with each proposal.

Just like in the JDT, the request for code completion arrives through jface to the editor's source viewer. The CSourceViewerConfiguration class creates the CCompletionProcessor and forwards the Code Assist request to it. The CCompletionProcessor forwards the request in turn to the current document's working copy for processing. Completion proposals are eventually sent to the completion requestor.

The working copy of the current document will use a CCompletionEngine to compute proposals. In CDT, code completion will consist of three main parts: Parsing using a completion parser, searching for symbols with certain criteria, and computing proposals and their relevance.

4.1 The Completion Parser

Currently the CDT parser does not have a completion mode. A new mode for the CDT parser will be implemented for code completion. Given a Translation unit and a cursor position, the parser will figure out what is the current completion scope. It will also predict the completion node, which indicates the types of proposals to look for in the given completion scope. Finally, the completion parser will return the prefix, if any, that all proposals should match.

In the example Single Name Reference, the completion scope in which search should take place would be the AST node that represents the function foo(). The completion node would be of type CompletionOnSingleNameReference, and the types of proposals to look for would be global variables, local variables, methods, keywords, and classes accessible from within that scope. The prefix to match would be "a".  In the example Basic Qualified Name Reference , the completion scope to search in would be the AST node that represents the class D. The predicted completion node would be of type CompletionOnQualifiedNameReference, and what to look for would be methods and fields of that class scope (including all its hierarchy). The prefix to match in this case is also "a".

4.2 The Symbol Table Lookups

After parsing a Translation Unit in CDT and following includes, the Symbol Table has information about all symbols in this translation unit's lookup environment. We intend to make use of this ready to use information and look for symbols with certain criteria (e.g. prefix) in the translation unit's lookup environment.

Since the Symbol Table is internal to the parser and should not be accessed directly, lookup methods will be added to AST nodes, which could be thought of as wrappers for the Symbol Table. For example, an AST Node that implements the IASTScope will be able to search for all symbols that start with a certain prefix within the lookup environment of this scope. The result of search would be a list of all AST nodes matching the given criteria. AST Nodes also contain visibility information and can determine if one virtual function is hidden by another. This information will be used by the completion engine in computing the proposals and their relevance.

4.3 The Completion Engine

The Completion Engine will call the completion parser.  It will then examine the returned scope and completion node and look for all possible proposal types with the given prefix. If there is only one proposal, the Completion Engine might want to simply insert it in the current cursor position. Otherwise, proposals will be ordered according to their relevance and sent for display.

5. References

JDT source code.

Last Modified on January 14, 2003