Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: don't look for overshadow conflicts for symbols not in the scope #7001

Merged
merged 2 commits into from
Dec 4, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,18 @@ final class PcInlineValueProviderImpl(
}

private def symbolsUsedInDef(
symbol: Symbol,
rhs: Tree
): List[Symbol] = {
val classParents =
if (symbol != null) symbol.ownersIterator.filter(_.isType).toSet
else Set.empty

def validateSymbol(symbol: Symbol) =
!symbol.isSynthetic && !symbol.isImplicit &&
(!symbol.safeOwner.isType || symbol.safeOwner.isModuleClass || classParents
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about:

class O {
  val t = new T()
  import t._
  val bb = a + a

  class Inner {
    val a = 123
    val cc = <<bb>>
  }
}

both a's have a type as parent. We should differentiate Select and Ident. I think the logic is correct on Select, but not on Ident

Copy link
Contributor Author

@kasiaMarek kasiaMarek Dec 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found another example, where this logic fails but in a different way.

object O {
  def ==(o: O) = false
}
object P {
  def test() = {
   val isOne = O == O
    <<i>>sOne //claims it cannot inline
  }
}

Being concerned only with the first qualifier for select (this might need some special logic) should be a better approach. Ident was for sake of infix methods, I guess we should detect them and handle appropriately. (infix is also Select)

However, this will fail to cover overshadow connected to extension methods and implicit classes. But lets maybe make it into a followup issue.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

However, this will fail to cover overshadow connected to extension methods and implicit classes. But lets maybe make it into a followup issue.

Yeah, we should be able to check that separately.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also in your example reference to a gets turned into a Select in the typed tree.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's not great then 🤔 Maybe we can check the ident span in Select(ident: Ident, sel) to see if it actually exist in the code ?

Copy link
Contributor Author

@kasiaMarek kasiaMarek Dec 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed the approach and I check if symbols are in scope before inline and look for conflicts on these symbols. Seems like the simplest solution.

.exists(_ == symbol.safeOwner))

@tailrec
def collectNames(
symbols: List[Tree],
Expand All @@ -77,11 +87,8 @@ final class PcInlineValueProviderImpl(
case tree :: toTraverse => {
val nextSymbols =
tree match {
case id: Ident
if !id.symbol.isSynthetic && !id.symbol.isImplicit =>
id :: symbols
case s: Select if !s.symbol.isSynthetic && !s.symbol.isImplicit =>
s :: symbols
case id: Ident if validateSymbol(id.symbol) => id :: symbols
case s: Select if validateSymbol(s.symbol) => s :: symbols
case _ => symbols
}
collectNames(nextSymbols, toTraverse ++ tree.children)
Expand All @@ -99,7 +106,7 @@ final class PcInlineValueProviderImpl(
.drop(1)
.exists(e => e.isTerm)
val allreferences = allOccurences.filterNot(_.isDefn)
val symbols = symbolsUsedInDef(definition.tree.rhs)
val symbols = symbolsUsedInDef(definition.tree.symbol, definition.tree.rhs)
def inlineAll() =
makeRefs(allreferences, symbols).right
.map((true, _))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ final class PcInlineValueProviderImpl(
DefinitionTree(defn, pos)
}
.toRight(Errors.didNotFindDefinition)
symbols = symbolsUsedInDefn(definition.tree.rhs)
symbols = symbolsUsedInDefn(definition.tree.symbol, definition.tree.rhs)
references <- getReferencesToInline(definition, allOccurences, symbols)
yield
val (deleteDefinition, refsEdits) = references
Expand Down Expand Up @@ -106,16 +106,25 @@ final class PcInlineValueProviderImpl(
val adjustedEnd = extend(pos.end - 1, ')', 1) + 1
text.slice(adjustedStart, adjustedEnd).mkString

/**
* Return all scope symbols used in this
*/
private def symbolsUsedInDefn(
symbol: Symbol,
rhs: Tree
): List[Symbol] =
val classParents =
if (symbol != null) symbol.ownersIterator.filter(_.isType).toSet
else Set.empty

def collectNames(
symbols: List[Symbol],
tree: Tree,
): List[Symbol] =
tree match
case id: (Ident | Select)
if !id.symbol.is(Synthetic) && !id.symbol.is(Implicit) =>
if !id.symbol.is(Synthetic) && !id.symbol.is(Implicit) &&
(!id.symbol.owner.isType || id.symbol.owner.is(ModuleClass) || classParents.contains(id.symbol.owner)) =>
tree.symbol :: symbols
case _ => symbols

Expand Down
17 changes: 17 additions & 0 deletions tests/cross/src/test/scala/tests/pc/InlineValueSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,23 @@ class InlineValueSuite extends BaseCodeActionSuite with CommonMtagsEnrichments {
|}""".stripMargin
)

checkEdit(
"i6924",
"""|object O {
| def test(n: Int) = {
| val isOne = n == 1
| <<i>>sOne
| }
|}
|""".stripMargin,
"""|object O {
| def test(n: Int) = {
| n == 1
| }
|}
|""".stripMargin
)

checkError(
"scoping-packages",
"""|package a
Expand Down
Loading