[nimsuggest] fix def call on identifier 2 times on the line (#20228)

- apparently TLineInfo's implementation of `==` ignores the column. After I fixed
the code to use exact TLineInfo comparison I fixed several other issues hidden
by that issue.

- Replaced `tuple[sym, info]` with `SymInfoPair`
This commit is contained in:
Ivan Yonchovski 2022-08-30 22:02:15 +03:00 • committed by GitHub
commit d4c0d35b32
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 76 additions and 48 deletions

View file

@ -53,6 +53,10 @@ type
concreteTypes*: seq[FullId] concreteTypes*: seq[FullId]
inst*: PInstantiation inst*: PInstantiation
SymInfoPair* = object
sym*: PSym
info*: TLineInfo
ModuleGraph* {.acyclic.} = ref object ModuleGraph* {.acyclic.} = ref object
ifaces*: seq[Iface] ## indexed by int32 fileIdx ifaces*: seq[Iface] ## indexed by int32 fileIdx
packed*: PackedModuleGraph packed*: PackedModuleGraph
@ -83,7 +87,7 @@ type
doStopCompile*: proc(): bool {.closure.} doStopCompile*: proc(): bool {.closure.}
usageSym*: PSym # for nimsuggest usageSym*: PSym # for nimsuggest
owners*: seq[PSym] owners*: seq[PSym]
suggestSymbols*: Table[FileIndex, seq[tuple[sym: PSym, info: TLineInfo]]] suggestSymbols*: Table[FileIndex, seq[SymInfoPair]]
suggestErrors*: Table[FileIndex, seq[Suggest]] suggestErrors*: Table[FileIndex, seq[Suggest]]
methods*: seq[tuple[methods: seq[PSym], dispatcher: PSym]] # needs serialization! methods*: seq[tuple[methods: seq[PSym], dispatcher: PSym]] # needs serialization!
systemModule*: PSym systemModule*: PSym
@ -374,12 +378,6 @@ template getPContext(): untyped =
when defined(nimsuggest): when defined(nimsuggest):
template onUse*(info: TLineInfo; s: PSym) = discard template onUse*(info: TLineInfo; s: PSym) = discard
template onDef*(info: TLineInfo; s: PSym) =
let c = getPContext()
if c.graph.config.suggestVersion == 3:
suggestSym(c.graph, info, s, c.graph.usageSym)
template onDefResolveForward*(info: TLineInfo; s: PSym) = discard template onDefResolveForward*(info: TLineInfo; s: PSym) = discard
else: else:
template onUse*(info: TLineInfo; s: PSym) = discard template onUse*(info: TLineInfo; s: PSym) = discard
@ -442,7 +440,7 @@ proc initModuleGraphFields(result: ModuleGraph) =
result.importStack = @[] result.importStack = @[]
result.inclToMod = initTable[FileIndex, FileIndex]() result.inclToMod = initTable[FileIndex, FileIndex]()
result.owners = @[] result.owners = @[]
result.suggestSymbols = initTable[FileIndex, seq[tuple[sym: PSym, info: TLineInfo]]]() result.suggestSymbols = initTable[FileIndex, seq[SymInfoPair]]()
result.suggestErrors = initTable[FileIndex, seq[Suggest]]() result.suggestErrors = initTable[FileIndex, seq[Suggest]]()
result.methods = @[] result.methods = @[]
initStrTable(result.compilerprocs) initStrTable(result.compilerprocs)
@ -641,7 +639,13 @@ func belongsToStdlib*(graph: ModuleGraph, sym: PSym): bool =
## Check if symbol belongs to the 'stdlib' package. ## Check if symbol belongs to the 'stdlib' package.
sym.getPackageSymbol.getPackageId == graph.systemModule.getPackageId sym.getPackageSymbol.getPackageId == graph.systemModule.getPackageId
iterator suggestSymbolsIter*(g: ModuleGraph): tuple[sym: PSym, info: TLineInfo] = proc `==`*(a, b: SymInfoPair): bool =
result = a.sym == b.sym and a.info.exactEquals(b.info)
proc fileSymbols*(graph: ModuleGraph, fileIdx: FileIndex): seq[SymInfoPair] =
result = graph.suggestSymbols.getOrDefault(fileIdx, @[]).deduplicate
iterator suggestSymbolsIter*(g: ModuleGraph): SymInfoPair =
for xs in g.suggestSymbols.values: for xs in g.suggestSymbols.values:
for x in xs.deduplicate: for x in xs.deduplicate:
yield x yield x

View file

@ -503,7 +503,7 @@ proc suggestSym*(g: ModuleGraph; info: TLineInfo; s: PSym; usageSym: var PSym; i
## misnamed: should be 'symDeclared' ## misnamed: should be 'symDeclared'
let conf = g.config let conf = g.config
when defined(nimsuggest): when defined(nimsuggest):
g.suggestSymbols.mgetOrPut(info.fileIndex, @[]).add (s, info) g.suggestSymbols.mgetOrPut(info.fileIndex, @[]).add SymInfoPair(sym: s, info: info)
if conf.suggestVersion == 0: if conf.suggestVersion == 0:
if s.allUsages.len == 0: if s.allUsages.len == 0:
@ -699,3 +699,16 @@ proc suggestSentinel*(c: PContext) =
dec(c.compilesContextId) dec(c.compilesContextId)
produceOutput(outputs, c.config) produceOutput(outputs, c.config)
when defined(nimsuggest):
proc onDef(graph: ModuleGraph, s: PSym, info: TLineInfo) =
if graph.config.suggestVersion == 3 and info.exactEquals(s.info):
suggestSym(graph, info, s, graph.usageSym)
template getPContext(): untyped =
when c is PContext: c
else: c.c
template onDef*(info: TLineInfo; s: PSym) =
let c = getPContext()
onDef(c.graph, s, info)

View file

@ -711,17 +711,16 @@ proc recompilePartially(graph: ModuleGraph, projectFileIdx = InvalidFileIdx) =
except Exception as e: except Exception as e:
myLog fmt "Failed clean recompilation:\n {e.msg} \n\n {e.getStackTrace()}" myLog fmt "Failed clean recompilation:\n {e.msg} \n\n {e.getStackTrace()}"
proc fileSymbols(graph: ModuleGraph, fileIdx: FileIndex): seq[tuple[sym: PSym, info: TLineInfo]] =
result = graph.suggestSymbols.getOrDefault(fileIdx, @[]).deduplicate
proc findSymData(graph: ModuleGraph, file: AbsoluteFile; line, col: int): proc findSymData(graph: ModuleGraph, file: AbsoluteFile; line, col: int):
tuple[sym: PSym, info: TLineInfo] = ref SymInfoPair =
let let
fileIdx = fileInfoIdx(graph.config, file) fileIdx = fileInfoIdx(graph.config, file)
trackPos = newLineInfo(fileIdx, line, col) trackPos = newLineInfo(fileIdx, line, col)
for (sym, info) in graph.fileSymbols(fileIdx): for s in graph.fileSymbols(fileIdx):
if isTracked(info, trackPos, sym.name.s.len): if isTracked(s.info, trackPos, s.sym.name.s.len):
return (sym, info) new(result)
result[] = s
break
proc markDirtyIfNeeded(graph: ModuleGraph, file: string, originalFileIdx: FileIndex) = proc markDirtyIfNeeded(graph: ModuleGraph, file: string, originalFileIdx: FileIndex) =
let sha = $sha1.secureHashFile(file) let sha = $sha1.secureHashFile(file)
@ -735,7 +734,7 @@ proc markDirtyIfNeeded(graph: ModuleGraph, file: string, originalFileIdx: FileIn
proc suggestResult(graph: ModuleGraph, sym: PSym, info: TLineInfo, defaultSection = ideNone) = proc suggestResult(graph: ModuleGraph, sym: PSym, info: TLineInfo, defaultSection = ideNone) =
let section = if defaultSection != ideNone: let section = if defaultSection != ideNone:
defaultSection defaultSection
elif sym.info == info: elif sym.info.exactEquals(info):
ideDef ideDef
else: else:
ideUse ideUse
@ -800,31 +799,31 @@ proc executeNoHooksV3(cmd: IdeCmd, file: AbsoluteFile, dirtyfile: AbsoluteFile,
case cmd case cmd
of ideDef: of ideDef:
let (sym, info) = graph.findSymData(file, line, col) let s = graph.findSymData(file, line, col)
if sym != nil: if not s.isNil:
graph.suggestResult(sym, sym.info) graph.suggestResult(s.sym, s.sym.info)
of ideType: of ideType:
let (sym, _) = graph.findSymData(file, line, col) let s = graph.findSymData(file, line, col)
if sym != nil: if not s.isNil:
let typeSym = sym.typ.sym let typeSym = s.sym.typ.sym
if typeSym != nil: if typeSym != nil:
graph.suggestResult(typeSym, typeSym.info, ideType) graph.suggestResult(typeSym, typeSym.info, ideType)
elif sym.typ.len != 0: elif s.sym.typ.len != 0:
let genericType = sym.typ[0].sym let genericType = s.sym.typ[0].sym
graph.suggestResult(genericType, genericType.info, ideType) graph.suggestResult(genericType, genericType.info, ideType)
of ideUse, ideDus: of ideUse, ideDus:
let symbol = graph.findSymData(file, line, col).sym let symbol = graph.findSymData(file, line, col)
if symbol != nil: if not symbol.isNil:
for (sym, info) in graph.suggestSymbolsIter: for s in graph.suggestSymbolsIter:
if sym == symbol: if s.sym == symbol.sym:
graph.suggestResult(sym, info) graph.suggestResult(s.sym, s.info)
of ideHighlight: of ideHighlight:
let sym = graph.findSymData(file, line, col).sym let sym = graph.findSymData(file, line, col)
if sym != nil: if not sym.isNil:
let usages = graph.fileSymbols(fileIndex).filterIt(it.sym == sym) let usages = graph.fileSymbols(fileIndex).filterIt(it.sym == sym.sym)
myLog fmt "Found {usages.len} usages in {file.string}" myLog fmt "Found {usages.len} usages in {file.string}"
for (sym, info) in usages: for s in usages:
graph.suggestResult(sym, info) graph.suggestResult(s.sym, s.info)
of ideRecompile: of ideRecompile:
graph.recompileFullProject() graph.recompileFullProject()
of ideChanged: of ideChanged:
@ -837,14 +836,12 @@ proc executeNoHooksV3(cmd: IdeCmd, file: AbsoluteFile, dirtyfile: AbsoluteFile,
let let
module = graph.getModule fileIndex module = graph.getModule fileIndex
symbols = graph.fileSymbols(fileIndex) symbols = graph.fileSymbols(fileIndex)
.filterIt(it.sym.info == it.info and .filterIt(it.sym.info.exactEquals(it.info) and
(it.sym.owner == module or (it.sym.owner == module or
it.sym.kind in searchableSymKinds)) it.sym.kind in searchableSymKinds))
for (sym, _) in symbols:
suggestResult( for s in symbols:
conf, graph.suggestResult(s.sym, s.info, ideOutline)
symToSuggest(graph, sym, false,
ideOutline, sym.info, 100, PrefixMatch.None, false, 0))
of ideChk: of ideChk:
myLog fmt "Reporting errors for {graph.suggestErrors.len} file(s)" myLog fmt "Reporting errors for {graph.suggestErrors.len} file(s)"
for sug in graph.suggestErrorsIter: for sug in graph.suggestErrorsIter:
@ -856,13 +853,12 @@ proc executeNoHooksV3(cmd: IdeCmd, file: AbsoluteFile, dirtyfile: AbsoluteFile,
suggestResult(graph.config, error) suggestResult(graph.config, error)
of ideGlobalSymbols: of ideGlobalSymbols:
var counter = 0 var counter = 0
for (sym, info) in graph.suggestSymbolsIter: for s in graph.suggestSymbolsIter:
if sfGlobal in sym.flags or sym.kind in searchableSymKinds: if (sfGlobal in s.sym.flags or s.sym.kind in searchableSymKinds) and
if contains(sym.name.s, file.string): s.sym.info == s.info:
if contains(s.sym.name.s, file.string):
inc counter inc counter
suggestResult(conf, graph.suggestResult(s.sym, s.info)
symToSuggest(graph, sym, isLocal=false,
ideDef, info, 100, PrefixMatch.None, false, 0))
# stop after first 100 results # stop after first 100 results
if counter > 100: if counter > 100:
break break

View file

@ -7,6 +7,8 @@ type
proc test(f: Foo) = proc test(f: Foo) =
echo f.ba#[!]#r echo f.ba#[!]#r
#[!]#
discard """ discard """
$nimsuggest --v3 --tester $file $nimsuggest --v3 --tester $file
>use $1 >use $1
@ -22,4 +24,8 @@ outline skProc tv3.test proc (f: Foo){.gcsafe, locks: 0.} $file 7 5 "" 100
sug skField bar string $file 5 4 "" 100 Prefix sug skField bar string $file 5 4 "" 100 Prefix
>globalSymbols test >globalSymbols test
def skProc tv3.test proc (f: Foo){.gcsafe, locks: 0.} $file 7 5 "" 100 def skProc tv3.test proc (f: Foo){.gcsafe, locks: 0.} $file 7 5 "" 100
>globalSymbols Foo
def skType tv3.Foo Foo $file 4 2 "" 100
>def $2
>use $2
""" """

View file

@ -0,0 +1,9 @@
let foo = 30
let bar = foo + fo#[!]#o + foo
discard """
$nimsuggest --v3 --tester $file
>def $1
def skLet tv3_definition.foo int $file 2 4 "" 100
"""