mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-28 17:04:41 +00:00
IC navigator: added support for include files (#17784)
* ic fixed navigator crash when track wrong/missed Also fixed an issue with getNimcacheDir not observing the outDir. * closer, but not sure how to test[skip ci][ci skip] * IC navigator: added support for include files * update * make posix happy via expandFilename * update Co-authored-by: Saem Ghani <saemghani+github@gmail.com>
This commit is contained in:
@@ -28,7 +28,7 @@ bootSwitch(usedNoGC, defined(nogc), "--gc:none")
|
||||
import
|
||||
os, msgs, options, nversion, condsyms, strutils, extccomp, platform,
|
||||
wordrecg, parseutils, nimblecmd, parseopt, sequtils, lineinfos,
|
||||
pathutils, strtabs
|
||||
pathutils, strtabs, pathnorm
|
||||
|
||||
from ast import eqTypeFlags, tfGcSafe, tfNoSideEffect
|
||||
|
||||
@@ -359,31 +359,52 @@ proc processCfgPath(conf: ConfigRef; path: string, info: TLineInfo): AbsoluteDir
|
||||
const
|
||||
errInvalidNumber = "$1 is not a valid number"
|
||||
|
||||
proc makeAbsolute(s: string): AbsoluteFile =
|
||||
if isAbsolute(s):
|
||||
AbsoluteFile pathnorm.normalizePath(s)
|
||||
else:
|
||||
AbsoluteFile pathnorm.normalizePath(os.getCurrentDir() / s)
|
||||
|
||||
proc setTrackingInfo(conf: ConfigRef; dirty, file, line, column: string,
|
||||
info: TLineInfo) =
|
||||
## set tracking info, common code for track, trackDirty, & ideTrack
|
||||
var ln, col: int
|
||||
if parseUtils.parseInt(line, ln) <= 0:
|
||||
localError(conf, info, errInvalidNumber % line)
|
||||
if parseUtils.parseInt(column, col) <= 0:
|
||||
localError(conf, info, errInvalidNumber % column)
|
||||
|
||||
let a = makeAbsolute(file)
|
||||
if dirty == "":
|
||||
conf.m.trackPos = newLineInfo(conf, a, ln, col)
|
||||
else:
|
||||
let dirtyOriginalIdx = fileInfoIdx(conf, a)
|
||||
if dirtyOriginalIdx.int32 >= 0:
|
||||
msgs.setDirtyFile(conf, dirtyOriginalIdx, makeAbsolute(dirty))
|
||||
conf.m.trackPos = newLineInfo(dirtyOriginalIdx, ln, col)
|
||||
|
||||
proc trackDirty(conf: ConfigRef; arg: string, info: TLineInfo) =
|
||||
var a = arg.split(',')
|
||||
if a.len != 4: localError(conf, info,
|
||||
"DIRTY_BUFFER,ORIGINAL_FILE,LINE,COLUMN expected")
|
||||
var line, column: int
|
||||
if parseUtils.parseInt(a[2], line) <= 0:
|
||||
localError(conf, info, errInvalidNumber % a[1])
|
||||
if parseUtils.parseInt(a[3], column) <= 0:
|
||||
localError(conf, info, errInvalidNumber % a[2])
|
||||
|
||||
let dirtyOriginalIdx = fileInfoIdx(conf, AbsoluteFile a[1])
|
||||
if dirtyOriginalIdx.int32 >= 0:
|
||||
msgs.setDirtyFile(conf, dirtyOriginalIdx, AbsoluteFile a[0])
|
||||
|
||||
conf.m.trackPos = newLineInfo(dirtyOriginalIdx, line, column)
|
||||
setTrackingInfo(conf, a[0], a[1], a[2], a[3], info)
|
||||
|
||||
proc track(conf: ConfigRef; arg: string, info: TLineInfo) =
|
||||
var a = arg.split(',')
|
||||
if a.len != 3: localError(conf, info, "FILE,LINE,COLUMN expected")
|
||||
var line, column: int
|
||||
if parseUtils.parseInt(a[1], line) <= 0:
|
||||
localError(conf, info, errInvalidNumber % a[1])
|
||||
if parseUtils.parseInt(a[2], column) <= 0:
|
||||
localError(conf, info, errInvalidNumber % a[2])
|
||||
conf.m.trackPos = newLineInfo(conf, AbsoluteFile a[0], line, column)
|
||||
setTrackingInfo(conf, "", a[0], a[1], a[2], info)
|
||||
|
||||
proc trackIde(conf: ConfigRef; cmd: IdeCmd, arg: string, info: TLineInfo) =
|
||||
## set the tracking info related to an ide cmd, supports optional dirty file
|
||||
var a = arg.split(',')
|
||||
case a.len
|
||||
of 4:
|
||||
setTrackingInfo(conf, a[0], a[1], a[2], a[3], info)
|
||||
of 3:
|
||||
setTrackingInfo(conf, "", a[0], a[1], a[2], info)
|
||||
else:
|
||||
localError(conf, info, "[DIRTY_BUFFER,]ORIGINAL_FILE,LINE,COLUMN expected")
|
||||
conf.ideCmd = cmd
|
||||
|
||||
proc dynlibOverride(conf: ConfigRef; switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
||||
if pass in {passCmd2, passPP}:
|
||||
@@ -851,17 +872,17 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||
expectNoArg(conf, switch, arg, pass, info)
|
||||
conf.ideCmd = ideSug
|
||||
of "def":
|
||||
expectNoArg(conf, switch, arg, pass, info)
|
||||
conf.ideCmd = ideDef
|
||||
expectArg(conf, switch, arg, pass, info)
|
||||
trackIde(conf, ideDef, arg, info)
|
||||
of "context":
|
||||
expectNoArg(conf, switch, arg, pass, info)
|
||||
conf.ideCmd = ideCon
|
||||
of "usages":
|
||||
expectNoArg(conf, switch, arg, pass, info)
|
||||
conf.ideCmd = ideUse
|
||||
expectArg(conf, switch, arg, pass, info)
|
||||
trackIde(conf, ideUse, arg, info)
|
||||
of "defusages":
|
||||
expectNoArg(conf, switch, arg, pass, info)
|
||||
conf.ideCmd = ideDus
|
||||
expectArg(conf, switch, arg, pass, info)
|
||||
trackIde(conf, ideDus, arg, info)
|
||||
of "stdout":
|
||||
processOnOffSwitchG(conf, {optStdout}, arg, pass, info)
|
||||
of "listfullpaths":
|
||||
|
||||
@@ -29,7 +29,7 @@ type
|
||||
PackedModule* = object ## the parts of a PackedEncoder that are part of the .rod file
|
||||
definedSymbols: string
|
||||
moduleFlags: TSymFlags
|
||||
includes: seq[(LitId, string)] # first entry is the module filename itself
|
||||
includes*: seq[(LitId, string)] # first entry is the module filename itself
|
||||
imports: seq[LitId] # the modules this module depends on
|
||||
toReplay*: PackedTree # pragmas and VM specific state to replay.
|
||||
topLevel*: PackedTree # top level statements
|
||||
|
||||
@@ -98,11 +98,31 @@ proc list(c: var NavContext; tree: PackedTree; sym: ItemId) =
|
||||
usage(c, tree.nodes[i].info, isDecl(tree, parent(NodePos i)))
|
||||
else: discard
|
||||
|
||||
proc searchForIncludeFile(g: ModuleGraph; fullPath: string): int =
|
||||
for i in 0..high(g.packed):
|
||||
for k in 1..high(g.packed[i].fromDisk.includes):
|
||||
# we start from 1 because the first "include" file is
|
||||
# the module's filename.
|
||||
if os.cmpPaths(g.packed[i].fromDisk.strings[g.packed[i].fromDisk.includes[k][0]], fullPath) == 0:
|
||||
return i
|
||||
return -1
|
||||
|
||||
proc nav(g: ModuleGraph) =
|
||||
# translate the track position to a packed position:
|
||||
let unpacked = g.config.m.trackPos
|
||||
let mid = unpacked.fileIndex
|
||||
let fileId = g.packed[int32 mid].fromDisk.strings.getKeyId(toFullPath(g.config, mid))
|
||||
var mid = unpacked.fileIndex.int
|
||||
|
||||
let fullPath = toFullPath(g.config, unpacked.fileIndex)
|
||||
|
||||
if g.packed[mid].status == undefined:
|
||||
# check if 'mid' is an include file of some other module:
|
||||
mid = searchForIncludeFile(g, fullPath)
|
||||
|
||||
if mid < 0:
|
||||
localError(g.config, unpacked, "unknown file name: " & fullPath)
|
||||
return
|
||||
|
||||
let fileId = g.packed[mid].fromDisk.strings.getKeyId(fullPath)
|
||||
|
||||
if fileId == LitId(0):
|
||||
internalError(g.config, unpacked, "cannot find a valid file ID")
|
||||
@@ -114,9 +134,9 @@ proc nav(g: ModuleGraph) =
|
||||
trackPos: PackedLineInfo(line: unpacked.line, col: unpacked.col, file: fileId),
|
||||
outputSep: if isDefined(g.config, "nimIcNavigatorTests"): ' ' else: '\t'
|
||||
)
|
||||
var symId = search(c, g.packed[int32 mid].fromDisk.topLevel)
|
||||
var symId = search(c, g.packed[mid].fromDisk.topLevel)
|
||||
if symId == EmptyItemId:
|
||||
symId = search(c, g.packed[int32 mid].fromDisk.bodies)
|
||||
symId = search(c, g.packed[mid].fromDisk.bodies)
|
||||
|
||||
if symId == EmptyItemId:
|
||||
localError(g.config, unpacked, "no symbol at this position")
|
||||
|
||||
@@ -582,6 +582,9 @@ template globalError*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "")
|
||||
template globalError*(conf: ConfigRef; info: TLineInfo, arg: string) =
|
||||
liMessage(conf, info, errGenerated, arg, doRaise, instLoc())
|
||||
|
||||
template globalError*(conf: ConfigRef; format: string, params: openArray[string]) =
|
||||
liMessage(conf, unknownLineInfo, errGenerated, format % params, doRaise, instLoc())
|
||||
|
||||
template localError*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") =
|
||||
liMessage(conf, info, msg, arg, doNothing, instLoc())
|
||||
|
||||
|
||||
@@ -701,7 +701,10 @@ proc getNimcacheDir*(conf: ConfigRef): AbsoluteDir =
|
||||
result = if not conf.nimcacheDir.isEmpty:
|
||||
conf.nimcacheDir
|
||||
elif conf.backend == backendJs:
|
||||
conf.projectPath / genSubDir
|
||||
if conf.outDir.isEmpty:
|
||||
conf.projectPath / genSubDir
|
||||
else:
|
||||
conf.outDir / genSubDir
|
||||
else:
|
||||
AbsoluteDir(getOsCacheDir() / splitFile(conf.projectName).name &
|
||||
nimcacheSuffix(conf))
|
||||
|
||||
@@ -490,7 +490,7 @@ proc icTests(r: var TResults; testsDir: string, cat: Category, options: string;
|
||||
writeOnly = " --incremental:writeonly "
|
||||
readOnly = " --incremental:readonly "
|
||||
incrementalOn = " --incremental:on -d:nimIcIntegrityChecks "
|
||||
navTestConfig = " --ic:on --defusages -d:nimIcNavigatorTests --hint[Conf]:off --warnings:off "
|
||||
navTestConfig = " --ic:on -d:nimIcNavigatorTests --hint[Conf]:off --warnings:off "
|
||||
|
||||
template test(x: untyped) =
|
||||
testSpecWithNimcache(r, makeRawTest(file, x & options, cat), nimcache)
|
||||
|
||||
2
tests/navigator/minclude.nim
Normal file
2
tests/navigator/minclude.nim
Normal file
@@ -0,0 +1,2 @@
|
||||
# An include file.
|
||||
foo(3)
|
||||
29
tests/navigator/tincludefile.nim
Normal file
29
tests/navigator/tincludefile.nim
Normal file
@@ -0,0 +1,29 @@
|
||||
discard """
|
||||
cmd: "nim check $options --defusages:$file,12,7 $file"
|
||||
nimout: '''def tincludefile_temp.nim(11, 10)
|
||||
usage tincludefile_temp.nim(12, 8)
|
||||
'''
|
||||
"""
|
||||
|
||||
|
||||
|
||||
|
||||
proc foo(x: int) =
|
||||
echo x
|
||||
|
||||
foo(3)
|
||||
echo "yes", 1 != 3
|
||||
|
||||
#!EDIT!#
|
||||
discard """
|
||||
cmd: "nim check $options --defusages:$file/../minclude.nim,2,2 $file"
|
||||
nimout: '''def tincludefile_temp.nim(10, 6)
|
||||
usage minclude.nim(2, 1)
|
||||
'''
|
||||
"""
|
||||
|
||||
|
||||
proc foo(x: int) =
|
||||
echo x
|
||||
|
||||
include minclude
|
||||
@@ -1,5 +1,5 @@
|
||||
discard """
|
||||
cmd: "nim check $options --track:$file,12,7 $file"
|
||||
cmd: "nim check $options --defusages:$file,12,7 $file"
|
||||
nimout: '''def tnav1_temp.nim(11, 10)
|
||||
usage tnav1_temp.nim(12, 8)
|
||||
'''
|
||||
@@ -16,7 +16,7 @@ echo "yes", 1 != 3
|
||||
|
||||
#!EDIT!#
|
||||
discard """
|
||||
cmd: "nim check $options --track:$file,15,2 $file"
|
||||
cmd: "nim check $options --defusages:$file,15,2 $file"
|
||||
nimout: '''def tnav1_temp.nim(12, 6)
|
||||
usage tnav1_temp.nim(15, 1)
|
||||
'''
|
||||
|
||||
Reference in New Issue
Block a user