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

Second steps towards scalafix.v1 #809

Merged
merged 32 commits into from
Aug 24, 2018
Merged

Second steps towards scalafix.v1 #809

merged 32 commits into from
Aug 24, 2018

Conversation

olafurpg
Copy link
Contributor

@olafurpg olafurpg commented Aug 22, 2018

This PR makes progress towards migrating the codebase to use scalafix.v1 instead of scalafix.v0

  • Migrate most syntactic rules to v1 API, the diff is minimal
  • s/v1.Sym/v1.Symbol/ now that scala.meta.Symbol is gone
  • New kids on the block: v1.Type and v1.Signature. Binary stable front-ends for their protobuf equivalents. Their only divergence from the protobuf data structures is that Scope is replaced with List[SymbolInfo] which is possible thanks to having a symbol table around. Most of the pain was writing equals and hashCode by hand since I think Type and Signature should be "data classes" with reasonable equality
  • Remove dead rules: xml literals, no finalize, no infer, disable unless
  • Remove references to v0 in v1 package

TODO:

  • ExplicitResultTypes
  • MissingFinal
  • Disable, it will stay unchanged on v0
  • RemoveUnusedTerms
  • RemoveUnusedImports
  • NoAutoTupling
  • s/v1.Type/v1.Tpe/
  • s/LintMessage/Diagnostic/

@olafurpg olafurpg requested a review from xeno-by August 22, 2018 21:21
@codecov
Copy link

codecov bot commented Aug 22, 2018

Codecov Report

Merging #809 into master will decrease coverage by 5.17%.
The diff coverage is 50.26%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #809      +/-   ##
==========================================
- Coverage   72.55%   67.37%   -5.18%     
==========================================
  Files         158      166       +8     
  Lines        3869     4067     +198     
  Branches      331      332       +1     
==========================================
- Hits         2807     2740      -67     
- Misses       1062     1327     +265
Impacted Files Coverage Δ
...c/main/scala/scalafix/testkit/DiffAssertions.scala 28.57% <ø> (ø) ⬆️
...c/main/scala/scalafix/internal/v0/LegacyRule.scala 75% <ø> (ø)
...x-core/src/main/scala/scalafix/v0/Denotation.scala 83.33% <ø> (ø) ⬆️
...rc/main/scala/scalafix/internal/rule/Disable.scala 100% <ø> (ø) ⬆️
...ts/unit/src/main/scala/scalafix/test/NoDummy.scala 100% <ø> (ø) ⬆️
...scalafix/internal/config/DisableSyntaxConfig.scala 100% <ø> (ø) ⬆️
...ala/scalafix/internal/reflect/RuleDecoderOps.scala 61.9% <ø> (ø) ⬆️
...calafix-core/src/main/scala/scalafix/package.scala 91.66% <ø> (ø) ⬆️
...a/scalafix/internal/patch/DeprecatedPatchOps.scala 52.63% <ø> (-15.79%) ⬇️
...cala/scalafix/internal/config/ScalafixConfig.scala 100% <ø> (ø) ⬆️
... and 95 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 1d9d610...87c3276. Read the comment docs.

def owner: Symbol = Symbol(info.symbol).owner
def name: String = info.name
def kind: SymbolKind = new SymbolKind(info)
def props: SymbolProperties = new SymbolProperties(info.properties)
Copy link
Contributor

Choose a reason for hiding this comment

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

How about inlining kind.isXXX and props.isXXX into SymbolInfo, so that it's info.isFinal and info.isMethod instead of info.props.isFinal and info.kind.isMethod?

Copy link
Contributor

Choose a reason for hiding this comment

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

case _ => scala.None
}
def isPublic: Boolean = a.isInstanceOf[s.PublicAccess]
def isNone: Boolean = a == s.NoAccess
Copy link
Contributor

Choose a reason for hiding this comment

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

An alternative approach to this API would be to replace privateWithin and protectedWithin with isPrivateWithin, isProtectedWithin and within. I think I like that better than the current API.

Copy link
Contributor

Choose a reason for hiding this comment

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

if (isVal) buf += "val"
if (isVar) buf += "var"
buf.mkString("SymbolProperties(", " ", ")")
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I wonder if we can use metap for that.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We can, but it requires making metap more flexible: scalameta/scalameta#1751

// def constant(c: s.Constant): Constant = c match {
// case s.NoConstant => throw new IllegalArgumentException(c.toString)
// case s.NoConstant => throw new IllegalArgumentException(c.toString)
// }
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this used anywhere?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's not, removed.

@@ -9,7 +9,7 @@ final class Symbol private (val value: String) {
def isGlobal: Boolean = value.isGlobal
def isLocal: Boolean = value.isLocal
def owner: Symbol = Symbol(value.owner)
def info(doc: SemanticDoc): SymbolInfo = doc.info(this)
def info(doc: SemanticDoc): Option[SymbolInfo] = doc.info(this)
Copy link
Contributor

Choose a reason for hiding this comment

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

Looks like there are two ways of doing the same thing: doc.info and symbol.info. How about we keep only the former?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I agree having two ways to do the same thing is a smell, I will go for Symbol.info with an implicit SemanticDoc instead. SemanticDoc is already implicit so that it can be passed to unapply methods.

We should update to latest scalafmt to automatically fix this with
`trailingCommas=never`
This makes it possible to experiement with different kinds of symbol matchers:

- prefix trees for instant lookups
- combined symbol matchers
This commit refactors Doc.tree to be computed on demand. This makes it
possible to implement rules that don't even parse the source file, which
could save a lot of redundant work when running on large codebases for
example when only targeting files that reference a single symbol.
This required exposing messages in the API
This aligns the scalafix API with semanticdb/lsp terminology.
It was always weird to write `messsage.message` to get the string
message from a `LintMessage`. The `LintMessage` name remains accessible
via forwarders for v0.
- LintMessage and LintCategory belong in the v0 package. Refactor v1
  rules to use Diagnostic directly instead.
- Diagnostic.apply is a simple constructor for simple use-cases
- LintDiagnostic doesn't need to be a trait, fewer extension points is better.
- remove dead code
@olafurpg
Copy link
Contributor Author

Will merge before this grows any bigger. All rules except Disable are now using scalafix.v1. The v1 API has been polished in several ways

  • Doc and SemanticDoc are small easy-to-understand classes and implementation details have moved to InternalDoc and InternalSemanticDoc that are in the scalafix.internal.v1 package.
  • Doc.tree is now lazy, meaning it's possible skip parsing a source file if the Input or TextDocument is not interesting. For example, if renaming a single symbol then it's possible to skip parsing files that don't reference that symbols. For large corpora, this can make a big difference.

These were originally copy-pasted before M10 was released.
This required introducing a new trait scalafix.v1.Symtab since
- we need access to the symtab in order to pretty-print symbols
- if we use SemanticDoc then we'd need to construct bogus Tree
  instances in order to construct a basic SymbolInfo.

We should not let `SemanticDoc` creep in everywhere as a dependency to
even the most trivial functionality.
@olafurpg
Copy link
Contributor Author

Gonna merge to unblock a PR from @MasseGuillaume on the website, happy to iterate further on this.

I believe it will be more interesting to discuss the new v1 API once the docs are in, which is next on my queue :)

@olafurpg olafurpg merged commit efa85ee into scalacenter:master Aug 24, 2018
@olafurpg olafurpg deleted the apis branch August 24, 2018 13:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants