Rename and Organize Imports ignore arguments of annotations
Scala plugin version: 3.0.1.v-2_10-201307101641-eff8147
Scala compiler version: 2.10.2.v20130530-074427-VFINAL-60d462ef6e
Scala library version: 2.10.2.v20130530-074427-VFINAL-60d462ef6e
Eclipse version: 4.2.2.v201302041200
Scala compiler version: 2.10.2.v20130530-074427-VFINAL-60d462ef6e
Scala library version: 2.10.2.v20130530-074427-VFINAL-60d462ef6e
Eclipse version: 4.2.2.v201302041200
package models
import org.springframework.data.neo4j.annotation.GraphId
import org.springframework.data.neo4j.annotation.Indexed
import org.springframework.data.neo4j.annotation.NodeEntity
import org.springframework.data.neo4j.support.index.IndexType
@NodeEntity
class User {
@GraphId
var id: java.lang.Long = _
@Indexed(indexName = "username", indexType = IndexType.FULLTEXT)
var username: String = _
// if you remove the following line and hit Organize Import, the import of IndexType will be removed, breaking compile for the @indexed annotation above
val test = IndexType.FULLTEXT
}
Leave a comment
on 2015-01-06 15:15 *
By Simon Schäfer
Component set to Refactoring
Version changed from 3.0.1-210 to 4.0.0
A minimal example to reproduce this bug can be found here: https://github.com/mlangc/scala-ide-experiments/tree/scala-ide-bug-1001793-2015-01-11
I'm currently trying to find out what can be done about this.
I'm currently trying to find out what can be done about this.
Unfortunately I didn't yet found a way to fix this using the current compiler API. Let me try to explain this with the following snippet (see https://github.com/mlangc/scala-refactoring/blob/organize-imports-and-annotations-1001726/org.scala-refactoring.library/src/test/scala/scala/tools/refactoring/tests/analysis/CompilationUnitDependenciesTest.scala#L1025):
The compiler gives as two trees for analyzing
So, the first tree,
I guess that taking a look at how the compiler actually transforms
import test._
package test {
object Constants {
final val X = 42
}
}
@AnAnnotation(Constants.X)
class Bug
The compiler gives as two trees for analyzing
@AnAnnotation(Constants.X)
, namely AnnotationInfo.original
and with Scala-2.11 also AnnotationInfo.tree
. They look like=======orig=======
Apply(
Select(New(Ident(AnAnnotation)), termNames.CONSTRUCTOR), List(
AssignOrNamedArg(
Ident(TermName("value")), Select(Ident(TermName("Constants")), TermName("X"))
)
)
)
=======tree=======
Apply(
Select(New(TypeTree()), termNames.CONSTRUCTOR), List(
AssignOrNamedArg(Ident(TermName("value")), Literal(Constant(42)))
)
)
So, the first tree,
orig
, does not tell us that Ident(TermName("Constants")), TermName("X")
actually is test.Constants.X
, and in the second tree, tree
, the compiler already filled in the constant 42
, which does not help us very much ether.I guess that taking a look at how the compiler actually transforms
Ident(TermName("Constants")), TermName("X")
into Literal(Constant(42))
might help, as to do so it clearly has to find out that Ident(TermName("Constants")), TermName("X")
references test.Constants.X
.
on 2015-02-22 10:39 *
By Mirko Stocker
Good analysis! The presentation-compiler shouldn't be doing constant-folding. You could raise this on scala-internals, maybe it can be fixed in the compiler.
on 2015-02-23 03:58 *
By Iulian Dragos
Note that the compiler has some support (via `-Xlint`) to check for unused imports. It does so during type-checking, so it avoids the problem of constant-folding.
One way to work around this issue is to never remove imports that point to a `final val` (or better, a constant type), since (only) they can be constant-folded.
One way to work around this issue is to never remove imports that point to a `final val` (or better, a constant type), since (only) they can be constant-folded.
on 2016-02-12 12:05 *
By Iulian Dragos
As far as I can tell, the presentation compiler isn't folding any constants. See this method (it is overridden in the IDE).
However, annotations are a different beast. The spec requires that all arguments to annotations have to be compile-time constants. There needs to be a different way to treat them, currently this is the code that does it
However, annotations are a different beast. The spec requires that all arguments to annotations have to be compile-time constants. There needs to be a different way to treat them, currently this is the code that does it
Note that this limitation also affects rename refactorings: Play around with this example, to see the problems we face here in action:
package com.github.mlangc.experiments;
public @interface AnAnnotation {
Class<?> value1();
Class<?> value2();
int value3();
}
package com.github.mlangc.experiments
import com.github.mlangc.experiments.test._
/*
* Try renaming or organizing imports here
*/
package test {
class TryRenameMe
class OrTryRenameMe
object Constants {
final val OrTryRenameMe = 42
}
}
@AnAnnotation(value1 = classOf[TryRenameMe], value2 = classOf[OrTryRenameMe], value3 = Constants.OrTryRenameMe)
class Bug
Move ticket to next milestone.