3. Assistance

In this chapter we describe all kind of tools assisting the user when writing code, i.e. content assist, quickfixes, quick assists, etc.

Not all features are yet implemented!

3.1. Content Assist

Content assist may change the document at various places at once. In those cases, it is important to prevent flickering in the editor. The FQNImporter provides a blue print how to adjust line numbers properly and scroll the viewport of the current editor to minimize flickering in the UI.

Completions not listed here as they are provided by template proposals:

  1. Classifier declaration template proposal

  2. Function declaration template proposal

  3. Getter/Setter pair template proposal

3.1.1. Complete Keywords

Complete keyword which are syntactically correct at a given location. Do not suggest completions which would lead to wrong code.

Keywords that contain only a single character are not proposed since they would pollute the proposal window and don’t offer added value.

Special attention has to be given to operators. Since they are modelled in the grammar and not as cross references, their validaty is purely syntactically. That is, there is no generic facility in Xtext, that allows to filter unapplicable operators as there is for cross references.

3.1.2. Complete Annotations

Annotations can be proposed depending on the following elements or the context.

3.1.3. Complete Identifier Reference

References to identifiers can be automatically completed. This is even true if the declaration is not imported yet, as the import may be automatically added as well.

Complete identifier references

The IDE supports auto-completion of an identifier referencing to a declaration.

  1. Complete type references.

  2. Complete function references.

  3. Complete variable references.

  4. Complete parameter references.

  5. If necessary, imports are added automatically to complete reference r to declaration D.

    Precondition

    -

    Postcondition

    bindrD

    r.name=D.name
    Dr.module

    NamedImportSpecifierNIS:
    WIS.importDecl.importedModule=D.module
    WildcardImportSpecifierWIS:

    Description

    There might be multiple declarations D in project (or in dependent projects) with D.name=r.name. If the declaration D is not local, then a named import may be created by the content assist:

    1. If the declaration D is local, no import is created

    2. If an import enabling access to the declaration already exists, no other import is created.

    3. If an alias already exists, the alias name is used, even if the prefix was different when the content assist was activated.

    4. If the import would conflict with an existing member, an alias is proposed along with the import. Linked editing helps to choose a proper alias.

    5. All imports from a single module are done within a single import declaration. The exception to this rule are wildcard imports that provide a simple name which is currently unused. In that case, a new import may be necessary to disambiguate the wildcard.

  6. If the identifier reference refers to a function (or method), an opening and a closing parenthesis are appended and the cursor is positioned between these two parentheses.

3.1.4. Complete Member Overrides

Complete Member Overrides Inside a classifier

A prefix of an inherited member can be used to autocomplete that to a complete declaration. This is in particular true for methods.

3.1.5. Constructor Completion

Constructor Completion

Constructor Completion Based on the declared fields and super constructor, constructor methods can be completed.

3.1.6. Complete Function Expression with Known Type

Complete Function Expression

If a function expression is used as an argument or assigned to a typed variable, the signature of the function can be derived from the type. This can be used to complete a function expression.

3.1.7. Complete Variable and Parameter Names

Type based completion of Variable and Parameter Names

Variable and parameter names can be completed based on the type. Camel case detection is used to propose different variations.

Completion of variables references see Complete Identifier Reference.

3.2. Quick Fixes

Quick fixes try to solve issues, i.e. errors or warnings, automatically. This is done by rewriting code, either at the location of the issue or at referenced locations.

In all cases, a quick fix must only be suggested if the following preconditions are fulfilled:

  1. All locations at which modifications have to be done must be writeable.

  2. If bindings are involved, e.g., names are to be changed, all previous bindings must remain similar. This might be more complicated as it seems!

3.2.1. N4JS Issue User data

As some quick fixes need more information to decide upfront which strategy to use, some issues provide additional data. These properties are defined in the file IssueUserDataKeys.java in the org.eclipse.n4js.validation package. They can for example be accessed by passing the according key to the getUserData method of an N4JSIssue instance. They are also available as array based Xtext Issue user data.

All available user data keys are described for each Issue code in N4JS Issue Fixes.

3.2.2. N4JS Issue Fixes

The principle idea is to provide a quick fix for every issue, if it is possible to automatically solve it.

3.2.2.1. Linking Issues

Linking issues are special in that they are created by the standard Xtext linker and use all the same built-in issue code Diagnostic.LINKING_DIAGNOSTIC. Therefore, we cannot refer to these issues using one of our custom N4JS issue codes.

Diagnostic.LINKING_DIAGNOSTIC

Couldn’t resolve reference to n

  1. Add missing import declaration for unresolved name n.

Precondition
  1. An exported identifiable element e with name n exists in another module m.

  2. e is visible from the given location.

Label

Import n - m

Postcondition

An import declaration was added such that name n is now resolvable at the given location and bound to e.

Description

Some important notes:

  1. A separate quick fix is proposed for each candidate element instead of having a single generic quick fix for adding imports and showing a dialog later (for example, create two quick fixes “Import class X from module M1" and “Import interface X from module M2" instead of a single quick fix “Add import for name X").
    This is unusual for quick fixes, because it means significant work has to be done upfront when creating the quick fix / modification proposals, which raises performance concerns. However,

    1. the JDT handles this the same way and

    2. this brings the implementation closer to content assist allowing more reuse, therefore this decision was taken.

  2. For consistency, matching of lower/upper/camel case is to be handled as in code completion during content assist. The same applies to display string formatting, esp. name formatting and coloring of element e and module m.

  3. Note that here we can make more assumptions than during import as part of content assist. For example, we know that the element is not imported yet (otherwise there would not be an error) and there won’t be a need for an alias and linked editing.

3.2.2.3. Visibility Issues
VIS_ILLEGAL_MEMBER_ACCESS

The memberType member is not visible.

  1. Change access modifier to protected/public or remove @Internal annotation.

    Precondition

    The file containing the declaration of member is modifiable

    Postcondition

    The access modifier has been changed so that member is visible at issue location.

    User Data
    • ACCESS_SUGGESTION The most restrictive modifier making the member visible.

    • DECLARATION_OBJECT_URI The EObject URI of the member declaration

This table shows the access modifier changes to perform to fix the visibility issue while maintaining the strongest access restrictions possible.

Access Modifier

Accessible From

Inside Module

Inside Project

Vendor Subtypes

Vendor Projects

Other Subtypes

Everywhere

private

-

project

protected@Internal

public@Internal

protected

public

project

-

-

protected@Internal

public@Internal

protected

public

protected@Internal

-

-

-

public@Internal

protected

public

protected

-

-

-

public@Internal

-

public

public@Internal

-

-

-

-

public

public

public

-

-

-

-

-

-

Member access modifier changes for quick fixes

VIS_ILLEGAL_FUN_ACCESS

The function f is not visible.

  1. Change access modifier to protected/public or remove @Internal annotation.

    Precondition

    Postcondition

    The access modifier has been changed so that f is visible at issue location.

    User Data
    • ACCESS_SUGGESTION The most restrictive modifier making the function visible.

    • DECLARATION_OBJECT_URI The EObject URI of the function declaration

VIS_ILLEGAL_TYPE_ACCESS

The type T is not visible.

  1. Change access modifier to protected/public or remove @Internal annotation.

    Precondition

    Postcondition

    The access modifier has been changed so that T is visible at issue location.

    User Data

    see VIS_ILLEGAL_FUN_ACCESS

VIS_ILLEGAL_VARIABLE_ACCESS

The variable v is not visible.

  1. Change access modifier to protected/public or remove @Internal annotation.

    Precondition

    Module containing v is writeable.

    Postcondition

    The access modifier has been changed so that v is visible at issue location.

    User Data

    see VIS_ILLEGAL_FUN_ACCESS

For type, variable and function visibility issues the following changes have to be made to solve the visibility issue:

Table 1. Type,function and variable access modifier changes for quick fixes

Access Modifier

Accessible From

Module

Project

Vendor

World

private

-

export project

export public@Internal

export public

project

-

export project

export public@Internal

export public

export project

-

-

export public@Internal

export public

export public@Internal

-

-

-

export public

export public

-

-

-

export public

3.2.2.4. Classifier Issues
CLF_EXTEND_FINAL

Cannot extend final class C.

  1. Remove @Final annotation in class C

    Precondition

    Postcondition

    ¬C.final

CLF_OBSERVABLE_MISSING

Class e0 extends observable class e1 and must therefore be annotated with @Observable.

  1. Add @Obervable annotation in class e0

    Precondition

    Postcondition

    e0.observable

CLF_OVERRIDE_ANNOTATION

The e0 overriding e1 must be annotated with @Override.

  1. Add @Override annotation to e0

    Precondition

    Label

    Add @Override

    Postcondition

    e0.override

CLF_OVERRIDE_FINAL

The e0 cannot override final e1.

  1. Remove @Final annotation in e1

    Precondition

    Postcondition

    ¬e1.final

CLF_OVERRIDE_VISIBILITY

The e0 cannot reduce the visibility of e1.

  1. Set access modifier of e0 to access modifier of e1

    Precondition

    Postcondition

    e0.acc==e1.acc

CLF_OVERRIDE_NON_EXISTENT

The e0 e1 must override or implement a e0 from a super class, consumed role or implemented interface.

  1. Remove @Override annotation in e1

    Precondition

    Label

    Remove @Override

    Postcondition

    ¬e1.override

CLF_REDEFINED_TYPE_NOT_SAME_TYPE

Type of e0 must equal type of e1 e2.

  1. Set declared type of e0 to declared type of e2

    Precondition

    Postcondition

    τe0=e2

CLF_REDEFINED_MEMBER_TYPE_INVALID

Type of e0 does not conform to e2 e1: e3.

  1. Set declared type of e0 to declared type of e1

    Precondition

    Postcondition

    τe0=e1

CLF_REDEFINED_METHOD_TYPE_CONFLICT

Signature of e0 does not conform to e1 e2: e3.

  1. Set declared type of e0 to declared type of e2

    Precondition

    Postcondition

    τe0=e2

CLF_MISSING_IMPLEMENTATION

Class C must either be defined abstract or implement m.

  1. Declare C as abstract

    Precondition

    Postcondition

    C.abstract

CLF_ABSTRACT_BODY

Abstract methods do not specify a body. for method M

  1. Remove abstract annotation from method.

    Precondition

    Postcondition

    ¬M.abstract

CLF_ABSTRACT_MISSING

The abstract e0 e1 in class C can only be defined in an abstract class.

  1. Declare C as abstract

    Precondition

    Postcondition

    C.abstract

    Multi appliable

    false

CLF_MISSING_BODY

The e0 e1 has to have either a body or must be defined abstract.

  1. Declare e1 as abstract

    Precondition

    Postcondition

    e1.abstract

CLF_EXT_EXTERNAL_N4JSD

e0 declared as external have to be placed in a file with file extension ’n4jsd’.

  1. Remove external annotation

    Precondition

    Postcondition

    ¬e0.external

  2. Change module file extension to n4jsd

    Precondition

    Postcondition

    module file extension is n4jsd

CLF_NOT_EXPORTED_NOT_PRIVATE

A e0 with visibility e1 must be marked as exported.

  1. Export e0

    Precondition

    Postcondition

    e0 is exported

3.2.2.5. Function Issues
FUN_BLOCK

Functions declarations should not be placed in blocks. Use a function expression or move the statement to the top of the outer function. with function F

  1. Change function declaration to function expression

    Precondition

    Postcondition
Variable vF.vee:v.name=Fv.expr.μ=FunctionExpressionv.expr.name=F.name,v.expr.body=F.body
Description

Change function declaration to function expression assigned to variable of the function name

3.2.2.6. Syntax Issues
AST_STR_FUN_NOT_NESTED

Functions must only be declared on script level or as part of other expressions

  1. Change function declaration to function expression assigned to variable of the function name

    Precondition

    Postcondition
Variable vF.vee:v.name=Fv.expr.μ=FunctionExpressionv.expr.name=F.name,v.expr.body=F.body
SYN_MODIFIER_BAD_ORDER

Modifiers should appear in this order: O

  1. Rearrange access modifiers

    Precondition

    Postcondition

    Modifiers are in order O

    Description

    Reorder the access modifiers to match the N4JS compliant order.

3.2.2.9. Expression Issues
EXP_WRONG_NUMBER_OF_TYPEARGS

Incorrect number of type arguments for T C: expected tpcount, got tacount.

  1. Remove superfluous arguments

    Precondition

    tacount>tpcount

    Postcondition

    tacount=tpcount

    Description
EXP_NUM_OF_ARGS_TOO_MANY

Incorrect number of arguments: expected fpcount, got argcount.

  1. Remove superfluous arguments

    Precondition

    argcount>fpcount

    Postcondition

    argcount=fpcount

    Description
EXP_CAST_UNNECESSARY

Unnecessary cast from S to T

  1. Remove cast

    Precondition

    Postcondition

    cast removed

    Description

3.4. Cleanup Operations

3.4.2. Organize Imports

Import statements can be cleaned up or automatically inserted by invoking Organize Imports. Organize Imports is available in the context menu Source / Organise imports , in menu Source > Organize imports or by hitting Cmd + Option +O (Win/Linux - Ctrl +Alt +O).

For a valid file without errors, this will result in the following actions:

  • Unused explicit imports will be removed.

  • Unused wildcard imports will be removed.

  • In each import statement the imported elements will be lexicographically sorted depending on the imported element’s name.

  • All import statements will be lexicographically sorted depending on the module specifier as major and the element name as minor key.

  • All import statements will be moved to the top of the file.

For a file with error-conditions of unresolved references, this will result in the automatic actions:

  • All ambiguous wildcard imports will be presented in one dialog, requesting the user to resolve the ambiguity.

  • Each uniquely resolvable unresolved Classifier will be added by a named import. The search scope is limited to the dependencies declared in the current project-setup.

No action will be taken, if …​

  • a classifier with name X is already imported by name from a module A and a unknown member of this classifier is marked. Even though the import of X from a different module B could remove this error, the semantic consequences could not be evaluated. The state will be left as-is.

If more then one option leads to a possible resolution the situation should be clarified using quick-fixes, e.g. if …​

  • more then one module provides an element, which would render a formerly unresolved reference to be valid.

  • for a wildcard-imported element X there are unknown members and a different module provides an element X containing the missing members. In such a case a named import of X would be proposed, optionally using an alias.