Skip to content

Commit

Permalink
Added autocomplete for constructors.
Browse files Browse the repository at this point in the history
This was done by adding an additional case to the completion logic
in ScalaCompletions.

To avoid problems with completion overwrites, similar to Eclipse Java
only tooltips are shown for constructor completion.

A known defect is the ability to complete constructors of classes with
mixins on the same line. See #1001950

Fix #1001272
  • Loading branch information
Daniel Chia committed Nov 5, 2013
1 parent 8ed264f commit 5159853
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 8 deletions.
Expand Up @@ -293,6 +293,19 @@ class CompletionTests {
runTest("t1001218/A.scala", false)(oraclePos8_14, oraclePos10_12, oraclePos12_12, oraclePos18_10)
}

@Test
def t1001272() {
val oraclePos16_18 = List("A(): t1001272.A", "A(Int): t1001272.A")
val oraclePos17_18 = List("B(): t1001272.B")
val oraclePos18_20 = List("E(Int): t1001272.D.E")
val oraclePos19_26 = List("InnerA(Int): t1001272.Test.a.InnerA")

val unit = scalaCompilationUnit("t1001272/A.scala")
reload(unit)

runTest("t1001272/A.scala", false)(oraclePos16_18, oraclePos17_18, oraclePos18_20, oraclePos19_26)
}

@Test
def t1001125() {
withCompletions("t1001125/Ticket1001125.scala") {
Expand Down
@@ -0,0 +1,20 @@
package t1001272

class A(a: Int) {
def this() = this(123)

class InnerA(i: Int)
}

class B extends A(1)

object D {
class E(i: Int)
}

object Test {
val a = new A( /*!*/ )
val b = new B( /*!*/ )
val e = new D.E( /*!*/ )
val ia = new a.InnerA( /*!*/ )
}
Expand Up @@ -281,7 +281,7 @@ class ScalaPresentationCompiler(project: ScalaProject, settings: Settings) exten
else if (sym.isModule) Object
else if (sym.isType) Type
else Val
val name = sym.decodedName
val name = if (sym.isConstructor) sym.owner.decodedName else sym.decodedName
val signature =
if (sym.isMethod) {
name +
Expand Down
Expand Up @@ -25,6 +25,7 @@ object CompletionContext {
trait ContextType
case object DefaultContext extends ContextType
case object ApplyContext extends ContextType
case object NewContext extends ContextType
case object ImportContext extends ContextType
}

Expand Down
Expand Up @@ -47,15 +47,23 @@ class ScalaCompletions extends HasLogger {
}
}

def completionFilter(sym: compiler.Symbol, viaView: compiler.Symbol = compiler.NoSymbol,
inherited: Option[Boolean] = None) = {
if (contextType == CompletionContext.NewContext)
sym.isConstructor && viaView == compiler.NoSymbol && !inherited.getOrElse(false)
else
!sym.isConstructor && nameMatches(sym)
}


val context = CompletionContext(contextType)

compiler.askOption { () =>
for (completion <- completions) {
val completionProposal = completion match {
case compiler.TypeMember(sym, tpe, true, inherited, viaView) if !sym.isConstructor && nameMatches(sym) =>
case compiler.TypeMember(sym, tpe, true, inherited, viaView) if completionFilter(sym, viaView, Some(inherited)) =>
Some(compiler.mkCompletionProposal(matchName, start, sym, tpe, inherited, viaView, context))
case compiler.ScopeMember(sym, tpe, true, _) if !sym.isConstructor && nameMatches(sym) =>
case compiler.ScopeMember(sym, tpe, true, _) if completionFilter(sym) =>
Some(compiler.mkCompletionProposal(matchName, start, sym, tpe, false, compiler.NoSymbol, context))
case _ => None
}
Expand Down Expand Up @@ -152,6 +160,9 @@ class ScalaCompletions extends HasLogger {
}

t1 match {
case Some(compiler.New(name)) =>
fillTypeCompletions(name.pos.endOrPoint, CompletionContext.NewContext,
Array(), name.pos.start, false)
case Some(compiler.Select(qualifier, name)) if qualifier.pos.isDefined && qualifier.pos.isRange =>
// completion on qualified type
fillTypeCompletions(qualifier.pos.end)
Expand All @@ -160,6 +171,9 @@ class ScalaCompletions extends HasLogger {
fillTypeCompletions(expr.pos.endOrPoint, CompletionContext.ImportContext)
case Some(compiler.Apply(fun, _)) =>
fun match {
case compiler.Select(qualifier: compiler.New, name) =>
fillTypeCompletions(qualifier.pos.endOrPoint, CompletionContext.NewContext,
Array(), qualifier.pos.start, false)
case compiler.Select(qualifier, name) if qualifier.pos.isDefined && qualifier.pos.isRange =>
fillTypeCompletions(qualifier.pos.endOrPoint, CompletionContext.ApplyContext,
name.decoded.toArray, qualifier.pos.end + 1, false)
Expand Down
Expand Up @@ -140,12 +140,13 @@ class ScalaCompletionProposal(proposal: CompletionProposal, selectionProvider: I
val d: IDocument = viewer.getDocument()
val overwrite = !insertCompletion ^ ((stateMask & SWT.CTRL) != 0)

val tooltipsOnly = context.contextType == CompletionContext.NewContext || context.contextType == CompletionContext.ApplyContext

val completionFullString = completionString(overwrite)
val importSize = withScalaFileAndSelection { (scalaSourceFile, textSelection) =>
var changes: List[TextChange] = Nil

// we don't have to change anything for Apply, since the full method is already specified
if (context.contextType != CompletionContext.ApplyContext) {
if (!tooltipsOnly) {
scalaSourceFile.withSourceFile { (sourceFile, _) =>
val endPos = if (overwrite) startPos + existingIdentifier(d, offset).getLength() else offset
changes :+= TextChange(sourceFile, startPos, endPos, completionFullString)
Expand Down Expand Up @@ -173,9 +174,7 @@ class ScalaCompletionProposal(proposal: CompletionProposal, selectionProvider: I
importStmt.headOption.map(_.text.length)
}

// similar to above, if we're in an apply context, we're not going to show
// anything in the editor (just doing tooltips)
if (context.contextType != CompletionContext.ApplyContext && context.contextType != CompletionContext.ImportContext) {
if (!tooltipsOnly && context.contextType != CompletionContext.ImportContext) {
if (!overwrite) selectionProvider match {
case viewer: ITextViewer if explicitParamNames.flatten.nonEmpty =>
addArgumentTemplates(d, viewer, completionFullString)
Expand Down

0 comments on commit 5159853

Please sign in to comment.