summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAndreas Rumpf <rumpf_a@web.de>2021-04-19 22:37:09 +0200
committerGitHub <noreply@github.com>2021-04-19 22:37:09 +0200
commit3b80f0dc8ef2bc9d2a981a7c92a6355dfc72b7ef (patch)
tree343dfdc727acde6e8e349661a94c208d1ceda9c0
parent24abe10aa8cdf3daa69854bba403ad4cee527503 (diff)
downloadNim-3b80f0dc8ef2bc9d2a981a7c92a6355dfc72b7ef.tar.gz
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>
-rw-r--r--compiler/commands.nim69
-rw-r--r--compiler/ic/ic.nim2
-rw-r--r--compiler/ic/navigator.nim28
-rw-r--r--compiler/msgs.nim3
-rw-r--r--compiler/options.nim5
-rw-r--r--testament/categories.nim2
-rw-r--r--tests/navigator/minclude.nim2
-rw-r--r--tests/navigator/tincludefile.nim29
-rw-r--r--tests/navigator/tnav1.nim4
9 files changed, 111 insertions, 33 deletions
diff --git a/compiler/commands.nim b/compiler/commands.nim
index e918979fb..5d6e45fb5 100644
--- a/compiler/commands.nim
+++ b/compiler/commands.nim
@@ -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":
diff --git a/compiler/ic/ic.nim b/compiler/ic/ic.nim
index a23685be7..d9a8756f1 100644
--- a/compiler/ic/ic.nim
+++ b/compiler/ic/ic.nim
@@ -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
diff --git a/compiler/ic/navigator.nim b/compiler/ic/navigator.nim
index b1a237cf7..cedf41579 100644
--- a/compiler/ic/navigator.nim
+++ b/compiler/ic/navigator.nim
@@ -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")
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index c1e1f9e39..39b10d7df 100644
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -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())
 
diff --git a/compiler/options.nim b/compiler/options.nim
index 5475410a4..c1ac6b1e0 100644
--- a/compiler/options.nim
+++ b/compiler/options.nim
@@ -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))
diff --git a/testament/categories.nim b/testament/categories.nim
index 4c3a0b1f5..d05112a25 100644
--- a/testament/categories.nim
+++ b/testament/categories.nim
@@ -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)
diff --git a/tests/navigator/minclude.nim b/tests/navigator/minclude.nim
new file mode 100644
index 000000000..f65ebfab9
--- /dev/null
+++ b/tests/navigator/minclude.nim
@@ -0,0 +1,2 @@
+# An include file.
+foo(3)
diff --git a/tests/navigator/tincludefile.nim b/tests/navigator/tincludefile.nim
new file mode 100644
index 000000000..f35ab2ec9
--- /dev/null
+++ b/tests/navigator/tincludefile.nim
@@ -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
diff --git a/tests/navigator/tnav1.nim b/tests/navigator/tnav1.nim
index d7c6f63e2..b6bbdbf19 100644
--- a/tests/navigator/tnav1.nim
+++ b/tests/navigator/tnav1.nim
@@ -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)
   '''