added first version of a nimfind tool for the poor souls that don't have a good nimsuggest integretation

This commit is contained in:
Andreas Rumpf 2018-11-14 16:04:45 +01:00
commit 6e8ed8c6fa
11 changed files with 326 additions and 52 deletions

View file

@ -63,6 +63,9 @@ type
cacheCounters*: Table[string, BiggestInt] cacheCounters*: Table[string, BiggestInt]
cacheTables*: Table[string, BTree[string, PNode]] cacheTables*: Table[string, BTree[string, PNode]]
passes*: seq[TPass] passes*: seq[TPass]
onDefinition*: proc (graph: ModuleGraph; s: PSym; info: TLineInfo) {.nimcall.}
onDefinitionResolveForward*: proc (graph: ModuleGraph; s: PSym; info: TLineInfo) {.nimcall.}
onUsage*: proc (graph: ModuleGraph; s: PSym; info: TLineInfo) {.nimcall.}
TPassContext* = object of RootObj # the pass's context TPassContext* = object of RootObj # the pass's context
PPassContext* = ref TPassContext PPassContext* = ref TPassContext
@ -78,6 +81,32 @@ type
proc hash*(x: FileIndex): Hash {.borrow.} proc hash*(x: FileIndex): Hash {.borrow.}
when defined(nimfind):
template onUse*(info: TLineInfo; s: PSym) =
when compiles(c.c.graph):
if c.c.graph.onUsage != nil: c.c.graph.onUsage(c.c.graph, s, info)
else:
if c.graph.onUsage != nil: c.graph.onUsage(c.graph, s, info)
template onDef*(info: TLineInfo; s: PSym) =
when compiles(c.c.graph):
if c.c.graph.onDefinition != nil: c.c.graph.onDefinition(c.c.graph, s, info)
else:
if c.graph.onDefinition != nil: c.graph.onDefinition(c.graph, s, info)
template onDefResolveForward*(info: TLineInfo; s: PSym) =
when compiles(c.c.graph):
if c.c.graph.onDefinitionResolveForward != nil:
c.c.graph.onDefinitionResolveForward(c.c.graph, s, info)
else:
if c.graph.onDefinitionResolveForward != nil:
c.graph.onDefinitionResolveForward(c.graph, s, info)
else:
template onUse*(info: TLineInfo; s: PSym) = discard
template onDef*(info: TLineInfo; s: PSym) = discard
template onDefResolveForward*(info: TLineInfo; s: PSym) = discard
proc stopCompile*(g: ModuleGraph): bool {.inline.} = proc stopCompile*(g: ModuleGraph): bool {.inline.} =
result = g.doStopCompile != nil and g.doStopCompile() result = g.doStopCompile != nil and g.doStopCompile()

View file

@ -18,7 +18,7 @@ import
evaltempl, patterns, parampatterns, sempass2, linter, semmacrosanity, evaltempl, patterns, parampatterns, sempass2, linter, semmacrosanity,
lowerings, pluginsupport, plugins/active, rod, lineinfos lowerings, pluginsupport, plugins/active, rod, lineinfos
from modulegraphs import ModuleGraph, PPassContext from modulegraphs import ModuleGraph, PPassContext, onUse, onDef, onDefResolveForward
when defined(nimfix): when defined(nimfix):
import nimfix/prettybase import nimfix/prettybase
@ -450,7 +450,7 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
pushInfoContext(c.config, nOrig.info, sym.detailedInfo) pushInfoContext(c.config, nOrig.info, sym.detailedInfo)
markUsed(c.config, n.info, sym, c.graph.usageSym) markUsed(c.config, n.info, sym, c.graph.usageSym)
styleCheckUse(n.info, sym) onUse(n.info, sym)
if sym == c.p.owner: if sym == c.p.owner:
globalError(c.config, n.info, "recursive dependency: '$1'" % sym.name.s) globalError(c.config, n.info, "recursive dependency: '$1'" % sym.name.s)

View file

@ -122,7 +122,7 @@ proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode;
if op == nil: if op == nil:
op = liftBody(c.c, t, c.kind, c.info) op = liftBody(c.c, t, c.kind, c.info)
markUsed(c.c.config, c.info, op, c.c.graph.usageSym) markUsed(c.c.config, c.info, op, c.c.graph.usageSym)
styleCheckUse(c.info, op) onUse(c.info, op)
body.add newAsgnCall(c.c, op, x, y) body.add newAsgnCall(c.c, op, x, y)
result = true result = true
@ -132,7 +132,7 @@ proc considerOverloadedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
let op = t.destructor let op = t.destructor
if op != nil: if op != nil:
markUsed(c.c.config, c.info, op, c.c.graph.usageSym) markUsed(c.c.config, c.info, op, c.c.graph.usageSym)
styleCheckUse(c.info, op) onUse(c.info, op)
body.add destructorCall(c.c, op, x) body.add destructorCall(c.c, op, x)
result = true result = true
of attachedAsgn: of attachedAsgn:
@ -143,7 +143,7 @@ proc considerOverloadedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
let op = t.deepCopy let op = t.deepCopy
if op != nil: if op != nil:
markUsed(c.c.config, c.info, op, c.c.graph.usageSym) markUsed(c.c.config, c.info, op, c.c.graph.usageSym)
styleCheckUse(c.info, op) onUse(c.info, op)
body.add newDeepCopyCall(op, x, y) body.add newDeepCopyCall(op, x, y)
result = true result = true

View file

@ -454,7 +454,7 @@ proc semResolvedCall(c: PContext, x: TCandidate,
assert x.state == csMatch assert x.state == csMatch
var finalCallee = x.calleeSym var finalCallee = x.calleeSym
markUsed(c.config, n.sons[0].info, finalCallee, c.graph.usageSym) markUsed(c.config, n.sons[0].info, finalCallee, c.graph.usageSym)
styleCheckUse(n.sons[0].info, finalCallee) onUse(n.sons[0].info, finalCallee)
assert finalCallee.ast != nil assert finalCallee.ast != nil
if x.hasFauxMatch: if x.hasFauxMatch:
result = x.call result = x.call
@ -562,7 +562,7 @@ proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode =
var newInst = generateInstance(c, s, m.bindings, n.info) var newInst = generateInstance(c, s, m.bindings, n.info)
newInst.typ.flags.excl tfUnresolved newInst.typ.flags.excl tfUnresolved
markUsed(c.config, n.info, s, c.graph.usageSym) markUsed(c.config, n.info, s, c.graph.usageSym)
styleCheckUse(n.info, s) onUse(n.info, s)
result = newSymNode(newInst, n.info) result = newSymNode(newInst, n.info)
proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode = proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =

View file

@ -25,7 +25,7 @@ const
proc semTemplateExpr(c: PContext, n: PNode, s: PSym, proc semTemplateExpr(c: PContext, n: PNode, s: PSym,
flags: TExprFlags = {}): PNode = flags: TExprFlags = {}): PNode =
markUsed(c.config, n.info, s, c.graph.usageSym) markUsed(c.config, n.info, s, c.graph.usageSym)
styleCheckUse(n.info, s) onUse(n.info, s)
pushInfoContext(c.config, n.info, s.detailedInfo) pushInfoContext(c.config, n.info, s.detailedInfo)
result = evalTemplate(n, s, getCurrOwner(c), c.config, efFromHlo in flags) result = evalTemplate(n, s, getCurrOwner(c), c.config, efFromHlo in flags)
if efNoSemCheck notin flags: result = semAfterMacroCall(c, n, result, s, flags) if efNoSemCheck notin flags: result = semAfterMacroCall(c, n, result, s, flags)
@ -265,7 +265,7 @@ proc semConv(c: PContext, n: PNode): PNode =
let status = checkConvertible(c, result.typ, it.typ) let status = checkConvertible(c, result.typ, it.typ)
if status in {convOK, convNotNeedeed}: if status in {convOK, convNotNeedeed}:
markUsed(c.config, n.info, it.sym, c.graph.usageSym) markUsed(c.config, n.info, it.sym, c.graph.usageSym)
styleCheckUse(n.info, it.sym) onUse(n.info, it.sym)
markIndirect(c, it.sym) markIndirect(c, it.sym)
return it return it
errorUseQualifier(c, n.info, op.sons[0].sym) errorUseQualifier(c, n.info, op.sons[0].sym)
@ -1036,7 +1036,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
case s.kind case s.kind
of skConst: of skConst:
markUsed(c.config, n.info, s, c.graph.usageSym) markUsed(c.config, n.info, s, c.graph.usageSym)
styleCheckUse(n.info, s) onUse(n.info, s)
case skipTypes(s.typ, abstractInst-{tyTypeDesc}).kind case skipTypes(s.typ, abstractInst-{tyTypeDesc}).kind
of tyNil, tyChar, tyInt..tyInt64, tyFloat..tyFloat128, of tyNil, tyChar, tyInt..tyInt64, tyFloat..tyFloat128,
tyTuple, tySet, tyUInt..tyUInt64: tyTuple, tySet, tyUInt..tyUInt64:
@ -1061,7 +1061,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
if efNoEvaluateGeneric in flags and s.ast[genericParamsPos].len > 0 or if efNoEvaluateGeneric in flags and s.ast[genericParamsPos].len > 0 or
(n.kind notin nkCallKinds and s.requiredParams > 0): (n.kind notin nkCallKinds and s.requiredParams > 0):
markUsed(c.config, n.info, s, c.graph.usageSym) markUsed(c.config, n.info, s, c.graph.usageSym)
styleCheckUse(n.info, s) onUse(n.info, s)
result = symChoice(c, n, s, scClosed) result = symChoice(c, n, s, scClosed)
else: else:
result = semMacroExpr(c, n, n, s, flags) result = semMacroExpr(c, n, n, s, flags)
@ -1070,13 +1070,13 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
(n.kind notin nkCallKinds and s.requiredParams > 0) or (n.kind notin nkCallKinds and s.requiredParams > 0) or
sfCustomPragma in sym.flags: sfCustomPragma in sym.flags:
markUsed(c.config, n.info, s, c.graph.usageSym) markUsed(c.config, n.info, s, c.graph.usageSym)
styleCheckUse(n.info, s) onUse(n.info, s)
result = symChoice(c, n, s, scClosed) result = symChoice(c, n, s, scClosed)
else: else:
result = semTemplateExpr(c, n, s, flags) result = semTemplateExpr(c, n, s, flags)
of skParam: of skParam:
markUsed(c.config, n.info, s, c.graph.usageSym) markUsed(c.config, n.info, s, c.graph.usageSym)
styleCheckUse(n.info, s) onUse(n.info, s)
if s.typ != nil and s.typ.kind == tyStatic and s.typ.n != nil: if s.typ != nil and s.typ.kind == tyStatic and s.typ.n != nil:
# XXX see the hack in sigmatch.nim ... # XXX see the hack in sigmatch.nim ...
return s.typ.n return s.typ.n
@ -1098,14 +1098,14 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
localError(c.config, n.info, "illegal context for 'nimvm' magic") localError(c.config, n.info, "illegal context for 'nimvm' magic")
markUsed(c.config, n.info, s, c.graph.usageSym) markUsed(c.config, n.info, s, c.graph.usageSym)
styleCheckUse(n.info, s) onUse(n.info, s)
result = newSymNode(s, n.info) result = newSymNode(s, n.info)
# We cannot check for access to outer vars for example because it's still # We cannot check for access to outer vars for example because it's still
# not sure the symbol really ends up being used: # not sure the symbol really ends up being used:
# var len = 0 # but won't be called # var len = 0 # but won't be called
# genericThatUsesLen(x) # marked as taking a closure? # genericThatUsesLen(x) # marked as taking a closure?
of skGenericParam: of skGenericParam:
styleCheckUse(n.info, s) onUse(n.info, s)
if s.typ.kind == tyStatic: if s.typ.kind == tyStatic:
result = newSymNode(s, n.info) result = newSymNode(s, n.info)
result.typ = s.typ result.typ = s.typ
@ -1116,7 +1116,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
return n return n
of skType: of skType:
markUsed(c.config, n.info, s, c.graph.usageSym) markUsed(c.config, n.info, s, c.graph.usageSym)
styleCheckUse(n.info, s) onUse(n.info, s)
if s.typ.kind == tyStatic and s.typ.base.kind != tyNone and s.typ.n != nil: if s.typ.kind == tyStatic and s.typ.base.kind != tyNone and s.typ.n != nil:
return s.typ.n return s.typ.n
result = newSymNode(s, n.info) result = newSymNode(s, n.info)
@ -1138,7 +1138,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
# is the access to a public field or in the same module or in a friend? # is the access to a public field or in the same module or in a friend?
doAssert f == s doAssert f == s
markUsed(c.config, n.info, f, c.graph.usageSym) markUsed(c.config, n.info, f, c.graph.usageSym)
styleCheckUse(n.info, f) onUse(n.info, f)
result = newNodeIT(nkDotExpr, n.info, f.typ) result = newNodeIT(nkDotExpr, n.info, f.typ)
result.add makeDeref(newSymNode(p.selfSym)) result.add makeDeref(newSymNode(p.selfSym))
result.add newSymNode(f) # we now have the correct field result.add newSymNode(f) # we now have the correct field
@ -1151,11 +1151,11 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
ty = skipTypes(ty.sons[0], skipPtrs) ty = skipTypes(ty.sons[0], skipPtrs)
# old code, not sure if it's live code: # old code, not sure if it's live code:
markUsed(c.config, n.info, s, c.graph.usageSym) markUsed(c.config, n.info, s, c.graph.usageSym)
styleCheckUse(n.info, s) onUse(n.info, s)
result = newSymNode(s, n.info) result = newSymNode(s, n.info)
else: else:
markUsed(c.config, n.info, s, c.graph.usageSym) markUsed(c.config, n.info, s, c.graph.usageSym)
styleCheckUse(n.info, s) onUse(n.info, s)
result = newSymNode(s, n.info) result = newSymNode(s, n.info)
proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
@ -1178,7 +1178,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
else: else:
markUsed(c.config, n.sons[1].info, s, c.graph.usageSym) markUsed(c.config, n.sons[1].info, s, c.graph.usageSym)
result = semSym(c, n, s, flags) result = semSym(c, n, s, flags)
styleCheckUse(n.sons[1].info, s) onUse(n.sons[1].info, s)
return return
n.sons[0] = semExprWithType(c, n.sons[0], flags+{efDetermineType}) n.sons[0] = semExprWithType(c, n.sons[0], flags+{efDetermineType})
@ -1241,7 +1241,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
result.info = n.info result.info = n.info
result.typ = ty result.typ = ty
markUsed(c.config, n.info, f, c.graph.usageSym) markUsed(c.config, n.info, f, c.graph.usageSym)
styleCheckUse(n.info, f) onUse(n.info, f)
return return
of tyObject, tyTuple: of tyObject, tyTuple:
if ty.n != nil and ty.n.kind == nkRecList: if ty.n != nil and ty.n.kind == nkRecList:
@ -1272,7 +1272,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
if fieldVisible(c, f): if fieldVisible(c, f):
# is the access to a public field or in the same module or in a friend? # is the access to a public field or in the same module or in a friend?
markUsed(c.config, n.sons[1].info, f, c.graph.usageSym) markUsed(c.config, n.sons[1].info, f, c.graph.usageSym)
styleCheckUse(n.sons[1].info, f) onUse(n.sons[1].info, f)
n.sons[0] = makeDeref(n.sons[0]) n.sons[0] = makeDeref(n.sons[0])
n.sons[1] = newSymNode(f) # we now have the correct field n.sons[1] = newSymNode(f) # we now have the correct field
n.typ = f.typ n.typ = f.typ
@ -1286,7 +1286,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
f = getSymFromList(ty.n, i) f = getSymFromList(ty.n, i)
if f != nil: if f != nil:
markUsed(c.config, n.sons[1].info, f, c.graph.usageSym) markUsed(c.config, n.sons[1].info, f, c.graph.usageSym)
styleCheckUse(n.sons[1].info, f) onUse(n.sons[1].info, f)
n.sons[0] = makeDeref(n.sons[0]) n.sons[0] = makeDeref(n.sons[0])
n.sons[1] = newSymNode(f) n.sons[1] = newSymNode(f)
n.typ = f.typ n.typ = f.typ
@ -1758,7 +1758,7 @@ proc semExpandToAst(c: PContext, n: PNode): PNode =
macroCall.sons[0] = newSymNode(expandedSym, macroCall.info) macroCall.sons[0] = newSymNode(expandedSym, macroCall.info)
markUsed(c.config, n.info, expandedSym, c.graph.usageSym) markUsed(c.config, n.info, expandedSym, c.graph.usageSym)
styleCheckUse(n.info, expandedSym) onUse(n.info, expandedSym)
if isCallExpr(macroCall): if isCallExpr(macroCall):
for i in countup(1, macroCall.len-1): for i in countup(1, macroCall.len-1):
@ -1783,7 +1783,7 @@ proc semExpandToAst(c: PContext, n: PNode): PNode =
let info = macroCall.sons[0].info let info = macroCall.sons[0].info
macroCall.sons[0] = newSymNode(cand, info) macroCall.sons[0] = newSymNode(cand, info)
markUsed(c.config, info, cand, c.graph.usageSym) markUsed(c.config, info, cand, c.graph.usageSym)
styleCheckUse(info, cand) onUse(info, cand)
# we just perform overloading resolution here: # we just perform overloading resolution here:
#n.sons[1] = semOverloadedCall(c, macroCall, macroCall, {skTemplate, skMacro}) #n.sons[1] = semOverloadedCall(c, macroCall, macroCall, {skTemplate, skMacro})
@ -2265,6 +2265,7 @@ proc semBlock(c: PContext, n: PNode; flags: TExprFlags): PNode =
n.sons[0] = newSymNode(labl, n.sons[0].info) n.sons[0] = newSymNode(labl, n.sons[0].info)
suggestSym(c.config, n.sons[0].info, labl, c.graph.usageSym) suggestSym(c.config, n.sons[0].info, labl, c.graph.usageSym)
styleCheckDef(c.config, labl) styleCheckDef(c.config, labl)
onDef(n[0].info, labl)
n.sons[1] = semExpr(c, n.sons[1], flags) n.sons[1] = semExpr(c, n.sons[1], flags)
n.typ = n.sons[1].typ n.typ = n.sons[1].typ
if isEmptyType(n.typ): n.kind = nkBlockStmt if isEmptyType(n.typ): n.kind = nkBlockStmt

View file

@ -76,14 +76,14 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
result = symChoice(c, n, s, scOpen) result = symChoice(c, n, s, scOpen)
of skTemplate: of skTemplate:
if macroToExpandSym(s): if macroToExpandSym(s):
styleCheckUse(n.info, s) onUse(n.info, s)
result = semTemplateExpr(c, n, s, {efNoSemCheck}) result = semTemplateExpr(c, n, s, {efNoSemCheck})
result = semGenericStmt(c, result, {}, ctx) result = semGenericStmt(c, result, {}, ctx)
else: else:
result = symChoice(c, n, s, scOpen) result = symChoice(c, n, s, scOpen)
of skMacro: of skMacro:
if macroToExpandSym(s): if macroToExpandSym(s):
styleCheckUse(n.info, s) onUse(n.info, s)
result = semMacroExpr(c, n, n, s, {efNoSemCheck}) result = semMacroExpr(c, n, n, s, {efNoSemCheck})
result = semGenericStmt(c, result, {}, ctx) result = semGenericStmt(c, result, {}, ctx)
else: else:
@ -96,20 +96,20 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
result = n result = n
else: else:
result = newSymNodeTypeDesc(s, n.info) result = newSymNodeTypeDesc(s, n.info)
styleCheckUse(n.info, s) onUse(n.info, s)
of skParam: of skParam:
result = n result = n
styleCheckUse(n.info, s) onUse(n.info, s)
of skType: of skType:
if (s.typ != nil) and if (s.typ != nil) and
(s.typ.flags * {tfGenericTypeParam, tfImplicitTypeParam} == {}): (s.typ.flags * {tfGenericTypeParam, tfImplicitTypeParam} == {}):
result = newSymNodeTypeDesc(s, n.info) result = newSymNodeTypeDesc(s, n.info)
else: else:
result = n result = n
styleCheckUse(n.info, s) onUse(n.info, s)
else: else:
result = newSymNode(s, n.info) result = newSymNode(s, n.info)
styleCheckUse(n.info, s) onUse(n.info, s)
proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags, proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags,
ctx: var GenericCtx): PNode = ctx: var GenericCtx): PNode =
@ -172,6 +172,7 @@ proc addTempDecl(c: PContext; n: PNode; kind: TSymKind) =
let s = newSymS(skUnknown, getIdentNode(c, n), c) let s = newSymS(skUnknown, getIdentNode(c, n), c)
addPrelimDecl(c, s) addPrelimDecl(c, s)
styleCheckDef(c.config, n.info, s, kind) styleCheckDef(c.config, n.info, s, kind)
onDef(n.info, s)
proc semGenericStmt(c: PContext, n: PNode, proc semGenericStmt(c: PContext, n: PNode,
flags: TSemGenericFlags, ctx: var GenericCtx): PNode = flags: TSemGenericFlags, ctx: var GenericCtx): PNode =
@ -230,7 +231,7 @@ proc semGenericStmt(c: PContext, n: PNode,
case s.kind case s.kind
of skMacro: of skMacro:
if macroToExpand(s) and sc.safeLen <= 1: if macroToExpand(s) and sc.safeLen <= 1:
styleCheckUse(fn.info, s) onUse(fn.info, s)
result = semMacroExpr(c, n, n, s, {efNoSemCheck}) result = semMacroExpr(c, n, n, s, {efNoSemCheck})
result = semGenericStmt(c, result, flags, ctx) result = semGenericStmt(c, result, flags, ctx)
else: else:
@ -239,7 +240,7 @@ proc semGenericStmt(c: PContext, n: PNode,
mixinContext = true mixinContext = true
of skTemplate: of skTemplate:
if macroToExpand(s) and sc.safeLen <= 1: if macroToExpand(s) and sc.safeLen <= 1:
styleCheckUse(fn.info, s) onUse(fn.info, s)
result = semTemplateExpr(c, n, s, {efNoSemCheck}) result = semTemplateExpr(c, n, s, {efNoSemCheck})
result = semGenericStmt(c, result, flags, ctx) result = semGenericStmt(c, result, flags, ctx)
else: else:
@ -262,17 +263,17 @@ proc semGenericStmt(c: PContext, n: PNode,
inc first inc first
of skGenericParam: of skGenericParam:
result.sons[0] = newSymNodeTypeDesc(s, fn.info) result.sons[0] = newSymNodeTypeDesc(s, fn.info)
styleCheckUse(fn.info, s) onUse(fn.info, s)
first = 1 first = 1
of skType: of skType:
# bad hack for generics: # bad hack for generics:
if (s.typ != nil) and (s.typ.kind != tyGenericParam): if (s.typ != nil) and (s.typ.kind != tyGenericParam):
result.sons[0] = newSymNodeTypeDesc(s, fn.info) result.sons[0] = newSymNodeTypeDesc(s, fn.info)
styleCheckUse(fn.info, s) onUse(fn.info, s)
first = 1 first = 1
else: else:
result.sons[0] = newSymNode(s, fn.info) result.sons[0] = newSymNode(s, fn.info)
styleCheckUse(fn.info, s) onUse(fn.info, s)
first = 1 first = 1
elif fn.kind == nkDotExpr: elif fn.kind == nkDotExpr:
result.sons[0] = fuzzyLookup(c, fn, flags, ctx, mixinContext) result.sons[0] = fuzzyLookup(c, fn, flags, ctx, mixinContext)

View file

@ -65,7 +65,7 @@ proc semBreakOrContinue(c: PContext, n: PNode): PNode =
incl(s.flags, sfUsed) incl(s.flags, sfUsed)
n.sons[0] = x n.sons[0] = x
suggestSym(c.config, x.info, s, c.graph.usageSym) suggestSym(c.config, x.info, s, c.graph.usageSym)
styleCheckUse(x.info, s) onUse(x.info, s)
else: else:
localError(c.config, n.info, errInvalidControlFlowX % s.name.s) localError(c.config, n.info, errInvalidControlFlowX % s.name.s)
else: else:
@ -363,6 +363,7 @@ proc semUsing(c: PContext; n: PNode): PNode =
for j in countup(0, length-3): for j in countup(0, length-3):
let v = semIdentDef(c, a.sons[j], skParam) let v = semIdentDef(c, a.sons[j], skParam)
styleCheckDef(c.config, v) styleCheckDef(c.config, v)
onDef(a[j].info, v)
v.typ = typ v.typ = typ
strTableIncl(c.signatures, v) strTableIncl(c.signatures, v)
else: else:
@ -494,6 +495,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
continue continue
var v = semIdentDef(c, a.sons[j], symkind) var v = semIdentDef(c, a.sons[j], symkind)
styleCheckDef(c.config, v) styleCheckDef(c.config, v)
onDef(a[j].info, v)
if sfGenSym notin v.flags and not isDiscardUnderscore(v): if sfGenSym notin v.flags and not isDiscardUnderscore(v):
addInterfaceDecl(c, v) addInterfaceDecl(c, v)
when oKeepVariableNames: when oKeepVariableNames:
@ -548,6 +550,7 @@ proc semConst(c: PContext, n: PNode): PNode =
checkSonsLen(a, 3, c.config) checkSonsLen(a, 3, c.config)
var v = semIdentDef(c, a.sons[0], skConst) var v = semIdentDef(c, a.sons[0], skConst)
styleCheckDef(c.config, v) styleCheckDef(c.config, v)
onDef(a[0].info, v)
var typ: PType = nil var typ: PType = nil
if a.sons[1].kind != nkEmpty: typ = semTypeNode(c, a.sons[1], nil) if a.sons[1].kind != nkEmpty: typ = semTypeNode(c, a.sons[1], nil)
@ -591,6 +594,7 @@ proc symForVar(c: PContext, n: PNode): PSym =
let m = if n.kind == nkPragmaExpr: n.sons[0] else: n let m = if n.kind == nkPragmaExpr: n.sons[0] else: n
result = newSymG(skForVar, m, c) result = newSymG(skForVar, m, c)
styleCheckDef(c.config, result) styleCheckDef(c.config, result)
onDef(n.info, result)
if n.kind == nkPragmaExpr: if n.kind == nkPragmaExpr:
pragma(c, result, n.sons[1], forVarPragmas) pragma(c, result, n.sons[1], forVarPragmas)
@ -696,7 +700,7 @@ proc handleCaseStmtMacro(c: PContext; n: PNode): PNode =
if r.state == csMatch: if r.state == csMatch:
var match = r.calleeSym var match = r.calleeSym
markUsed(c.config, n[0].info, match, c.graph.usageSym) markUsed(c.config, n[0].info, match, c.graph.usageSym)
styleCheckUse(n[0].info, match) onUse(n[0].info, match)
# but pass 'n' to the 'match' macro, not 'n[0]': # but pass 'n' to the 'match' macro, not 'n[0]':
r.call.sons[1] = n r.call.sons[1] = n
@ -880,6 +884,7 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) =
if typsym.isNil: if typsym.isNil:
s = semIdentDef(c, name[1], skType) s = semIdentDef(c, name[1], skType)
styleCheckDef(c.config, s) styleCheckDef(c.config, s)
onDef(name[1].info, s)
s.typ = newTypeS(tyObject, c) s.typ = newTypeS(tyObject, c)
s.typ.sym = s s.typ.sym = s
s.flags.incl sfForward s.flags.incl sfForward
@ -894,6 +899,7 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) =
else: else:
s = semIdentDef(c, name, skType) s = semIdentDef(c, name, skType)
styleCheckDef(c.config, s) styleCheckDef(c.config, s)
onDef(name.info, s)
s.typ = newTypeS(tyForward, c) s.typ = newTypeS(tyForward, c)
s.typ.sym = s # process pragmas: s.typ.sym = s # process pragmas:
if name.kind == nkPragmaExpr: if name.kind == nkPragmaExpr:
@ -1625,6 +1631,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
else: else:
implicitPragmas(c, s, n, validPragmas) implicitPragmas(c, s, n, validPragmas)
styleCheckDef(c.config, s) styleCheckDef(c.config, s)
onDef(n[namePos].info, s)
else: else:
if n.sons[pragmasPos].kind != nkEmpty: if n.sons[pragmasPos].kind != nkEmpty:
pragma(c, s, n.sons[pragmasPos], validPragmas) pragma(c, s, n.sons[pragmasPos], validPragmas)
@ -1638,6 +1645,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
localError(c.config, n.sons[pragmasPos].info, errPragmaOnlyInHeaderOfProcX % localError(c.config, n.sons[pragmasPos].info, errPragmaOnlyInHeaderOfProcX %
("'" & proto.name.s & "' from " & c.config$proto.info)) ("'" & proto.name.s & "' from " & c.config$proto.info))
styleCheckDef(c.config, s) styleCheckDef(c.config, s)
onDefResolveForward(n[namePos].info, proto)
if sfForward notin proto.flags and proto.magic == mNone: if sfForward notin proto.flags and proto.magic == mNone:
wrongRedefinition(c, n.info, proto.name.s, proto.info) wrongRedefinition(c, n.info, proto.name.s, proto.info)
excl(proto.flags, sfForward) excl(proto.flags, sfForward)

View file

@ -160,7 +160,7 @@ proc onlyReplaceParams(c: var TemplCtx, n: PNode): PNode =
if s.owner == c.owner and s.kind == skParam: if s.owner == c.owner and s.kind == skParam:
incl(s.flags, sfUsed) incl(s.flags, sfUsed)
result = newSymNode(s, n.info) result = newSymNode(s, n.info)
styleCheckUse(n.info, s) onUse(n.info, s)
else: else:
for i in 0 ..< n.safeLen: for i in 0 ..< n.safeLen:
result.sons[i] = onlyReplaceParams(c, n.sons[i]) result.sons[i] = onlyReplaceParams(c, n.sons[i])
@ -208,19 +208,20 @@ proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) =
# So we need only check the *current* scope. # So we need only check the *current* scope.
let s = localSearchInScope(c.c, considerQuotedIdent(c.c, ident)) let s = localSearchInScope(c.c, considerQuotedIdent(c.c, ident))
if s != nil and s.owner == c.owner and sfGenSym in s.flags: if s != nil and s.owner == c.owner and sfGenSym in s.flags:
styleCheckUse(n.info, s) onUse(n.info, s)
replaceIdentBySym(c.c, n, newSymNode(s, n.info)) replaceIdentBySym(c.c, n, newSymNode(s, n.info))
elif not (n.kind == nkSym and sfGenSym in n.sym.flags): elif not (n.kind == nkSym and sfGenSym in n.sym.flags):
let local = newGenSym(k, ident, c) let local = newGenSym(k, ident, c)
addPrelimDecl(c.c, local) addPrelimDecl(c.c, local)
styleCheckDef(c.c.config, n.info, local) styleCheckDef(c.c.config, n.info, local)
onDef(n.info, local)
replaceIdentBySym(c.c, n, newSymNode(local, n.info)) replaceIdentBySym(c.c, n, newSymNode(local, n.info))
else: else:
replaceIdentBySym(c.c, n, ident) replaceIdentBySym(c.c, n, ident)
proc semTemplSymbol(c: PContext, n: PNode, s: PSym): PNode = proc semTemplSymbol(c: PContext, n: PNode, s: PSym): PNode =
incl(s.flags, sfUsed) incl(s.flags, sfUsed)
# we do not call styleCheckUse here, as the identifier is not really # we do not call onUse here, as the identifier is not really
# resolved here. We will fixup the used identifiers later. # resolved here. We will fixup the used identifiers later.
case s.kind case s.kind
of skUnknown: of skUnknown:
@ -245,7 +246,7 @@ proc semRoutineInTemplName(c: var TemplCtx, n: PNode): PNode =
if s.owner == c.owner and (s.kind == skParam or sfGenSym in s.flags): if s.owner == c.owner and (s.kind == skParam or sfGenSym in s.flags):
incl(s.flags, sfUsed) incl(s.flags, sfUsed)
result = newSymNode(s, n.info) result = newSymNode(s, n.info)
styleCheckUse(n.info, s) onUse(n.info, s)
else: else:
for i in countup(0, safeLen(n) - 1): for i in countup(0, safeLen(n) - 1):
result.sons[i] = semRoutineInTemplName(c, n.sons[i]) result.sons[i] = semRoutineInTemplName(c, n.sons[i])
@ -261,6 +262,7 @@ proc semRoutineInTemplBody(c: var TemplCtx, n: PNode, k: TSymKind): PNode =
s.ast = n s.ast = n
addPrelimDecl(c.c, s) addPrelimDecl(c.c, s)
styleCheckDef(c.c.config, n.info, s) styleCheckDef(c.c.config, n.info, s)
onDef(n.info, s)
n.sons[namePos] = newSymNode(s, n.sons[namePos].info) n.sons[namePos] = newSymNode(s, n.sons[namePos].info)
else: else:
n.sons[namePos] = ident n.sons[namePos] = ident
@ -314,7 +316,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
if s.owner == c.owner and s.kind == skParam: if s.owner == c.owner and s.kind == skParam:
incl(s.flags, sfUsed) incl(s.flags, sfUsed)
result = newSymNode(s, n.info) result = newSymNode(s, n.info)
styleCheckUse(n.info, s) onUse(n.info, s)
elif contains(c.toBind, s.id): elif contains(c.toBind, s.id):
result = symChoice(c.c, n, s, scClosed) result = symChoice(c.c, n, s, scClosed)
elif contains(c.toMixin, s.name.id): elif contains(c.toMixin, s.name.id):
@ -324,7 +326,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
# var yz: T # var yz: T
incl(s.flags, sfUsed) incl(s.flags, sfUsed)
result = newSymNode(s, n.info) result = newSymNode(s, n.info)
styleCheckUse(n.info, s) onUse(n.info, s)
else: else:
result = semTemplSymbol(c.c, n, s) result = semTemplSymbol(c.c, n, s)
of nkBind: of nkBind:
@ -382,6 +384,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
let s = newGenSym(skLabel, n.sons[0], c) let s = newGenSym(skLabel, n.sons[0], c)
addPrelimDecl(c.c, s) addPrelimDecl(c.c, s)
styleCheckDef(c.c.config, s) styleCheckDef(c.c.config, s)
onDef(n[0].info, s)
n.sons[0] = newSymNode(s, n.sons[0].info) n.sons[0] = newSymNode(s, n.sons[0].info)
n.sons[1] = semTemplBody(c, n.sons[1]) n.sons[1] = semTemplBody(c, n.sons[1])
closeScope(c) closeScope(c)
@ -505,7 +508,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
if s.owner == c.owner and s.kind == skParam and if s.owner == c.owner and s.kind == skParam and
n.kind == nkAccQuoted and n.len == 1: n.kind == nkAccQuoted and n.len == 1:
incl(s.flags, sfUsed) incl(s.flags, sfUsed)
styleCheckUse(n.info, s) onUse(n.info, s)
return newSymNode(s, n.info) return newSymNode(s, n.info)
elif contains(c.toBind, s.id): elif contains(c.toBind, s.id):
return symChoice(c.c, n, s, scClosed) return symChoice(c.c, n, s, scClosed)
@ -553,6 +556,7 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
else: else:
s = semIdentVis(c, skTemplate, n.sons[0], {}) s = semIdentVis(c, skTemplate, n.sons[0], {})
styleCheckDef(c.config, s) styleCheckDef(c.config, s)
onDef(n[0].info, s)
# check parameter list: # check parameter list:
#s.scope = c.currentScope #s.scope = c.currentScope
pushOwner(c, s) pushOwner(c, s)
@ -635,7 +639,7 @@ proc semPatternBody(c: var TemplCtx, n: PNode): PNode =
# semtypes.addParamOrResult). Within the pattern we have to ensure # semtypes.addParamOrResult). Within the pattern we have to ensure
# to use the param with the proper type though: # to use the param with the proper type though:
incl(s.flags, sfUsed) incl(s.flags, sfUsed)
styleCheckUse(n.info, s) onUse(n.info, s)
let x = c.owner.typ.n.sons[s.position+1].sym let x = c.owner.typ.n.sons[s.position+1].sym
assert x.name == s.name assert x.name == s.name
result = newSymNode(x, n.info) result = newSymNode(x, n.info)

View file

@ -122,6 +122,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
if not isPure: strTableAdd(c.module.tab, e) if not isPure: strTableAdd(c.module.tab, e)
addSon(result.n, newSymNode(e)) addSon(result.n, newSymNode(e))
styleCheckDef(c.config, e) styleCheckDef(c.config, e)
onDef(e.info, e)
if sfGenSym notin e.flags: if sfGenSym notin e.flags:
if not isPure: addDecl(c, e) if not isPure: addDecl(c, e)
else: importPureEnumField(c, e) else: importPureEnumField(c, e)
@ -377,7 +378,7 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
result = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared}) result = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared})
if result != nil: if result != nil:
markUsed(c.config, n.info, result, c.graph.usageSym) markUsed(c.config, n.info, result, c.graph.usageSym)
styleCheckUse(n.info, result) onUse(n.info, result)
if result.kind == skParam and result.typ.kind == tyTypeDesc: if result.kind == skParam and result.typ.kind == tyTypeDesc:
# This is a typedesc param. is it already bound? # This is a typedesc param. is it already bound?
@ -466,6 +467,7 @@ proc semTuple(c: PContext, n: PNode, prev: PType): PType =
addSon(result.n, newSymNode(field)) addSon(result.n, newSymNode(field))
addSonSkipIntLit(result, typ) addSonSkipIntLit(result, typ)
styleCheckDef(c.config, a.sons[j].info, field) styleCheckDef(c.config, a.sons[j].info, field)
onDef(field.info, field)
if result.n.len == 0: result.n = nil if result.n.len == 0: result.n = nil
proc semIdentVis(c: PContext, kind: TSymKind, n: PNode, proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
@ -688,7 +690,6 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
else: rectype.sym else: rectype.sym
for i in countup(0, sonsLen(n)-3): for i in countup(0, sonsLen(n)-3):
var f = semIdentWithPragma(c, skField, n.sons[i], {sfExported}) var f = semIdentWithPragma(c, skField, n.sons[i], {sfExported})
styleCheckDef(c.config, n.sons[i].info, f)
suggestSym(c.config, n.sons[i].info, f, c.graph.usageSym) suggestSym(c.config, n.sons[i].info, f, c.graph.usageSym)
f.typ = typ f.typ = typ
f.position = pos f.position = pos
@ -703,6 +704,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
if a.kind == nkEmpty: addSon(father, newSymNode(f)) if a.kind == nkEmpty: addSon(father, newSymNode(f))
else: addSon(a, newSymNode(f)) else: addSon(a, newSymNode(f))
styleCheckDef(c.config, f) styleCheckDef(c.config, f)
onDef(f.info, f)
if a.kind != nkEmpty: addSon(father, a) if a.kind != nkEmpty: addSon(father, a)
of nkSym: of nkSym:
# This branch only valid during generic object # This branch only valid during generic object
@ -988,7 +990,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
of tyGenericParam: of tyGenericParam:
markUsed(c.config, info, paramType.sym, c.graph.usageSym) markUsed(c.config, info, paramType.sym, c.graph.usageSym)
styleCheckUse(info, paramType.sym) onUse(info, paramType.sym)
if tfWildcard in paramType.flags: if tfWildcard in paramType.flags:
paramType.flags.excl tfWildcard paramType.flags.excl tfWildcard
paramType.sym.kind = skType paramType.sym.kind = skType
@ -1110,6 +1112,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
rawAddSon(result, finalType) rawAddSon(result, finalType)
addParamOrResult(c, arg, kind) addParamOrResult(c, arg, kind)
styleCheckDef(c.config, a.sons[j].info, arg) styleCheckDef(c.config, a.sons[j].info, arg)
onDef(a[j].info, arg)
var r: PType var r: PType
if n.sons[0].kind != nkEmpty: if n.sons[0].kind != nkEmpty:
@ -1637,7 +1640,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
assignType(prev, t) assignType(prev, t)
result = prev result = prev
markUsed(c.config, n.info, n.sym, c.graph.usageSym) markUsed(c.config, n.info, n.sym, c.graph.usageSym)
styleCheckUse(n.info, n.sym) onUse(n.info, n.sym)
else: else:
if s.kind != skError: localError(c.config, n.info, errTypeExpected) if s.kind != skError: localError(c.config, n.info, errTypeExpected)
result = newOrPrevType(tyError, prev, c) result = newOrPrevType(tyError, prev, c)

View file

@ -13,7 +13,7 @@
import import
intsets, ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst, intsets, ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst,
magicsys, condsyms, idents, lexer, options, parampatterns, strutils, trees, magicsys, condsyms, idents, lexer, options, parampatterns, strutils, trees,
linter, lineinfos linter, lineinfos, modulegraphs
when (defined(booting) or defined(nimsuggest)) and not defined(leanCompiler): when (defined(booting) or defined(nimsuggest)) and not defined(leanCompiler):
import docgen import docgen
@ -2149,7 +2149,7 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
else: else:
# only one valid interpretation found: # only one valid interpretation found:
markUsed(m.c.config, arg.info, arg.sons[best].sym, m.c.graph.usageSym) markUsed(m.c.config, arg.info, arg.sons[best].sym, m.c.graph.usageSym)
styleCheckUse(arg.info, arg.sons[best].sym) onUse(arg.info, arg.sons[best].sym)
result = paramTypesMatchAux(m, f, arg.sons[best].typ, arg.sons[best], result = paramTypesMatchAux(m, f, arg.sons[best].typ, arg.sons[best],
argOrig) argOrig)
when false: when false:

228
tools/nimfind.nim Normal file
View file

@ -0,0 +1,228 @@
#
#
# The Nim Compiler
# (c) Copyright 2018 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## Nimfind is a tool that helps to give editors IDE like capabilities.
when not defined(nimcore):
{.error: "nimcore MUST be defined for Nim's core tooling".}
when not defined(nimfind):
{.error: "nimfind MUST be defined for Nim's nimfind tool".}
const Usage = """
Nimfind - Tool to find declarations or usages for Nim symbols
Usage:
nimfind [options] file.nim:line:col
Options:
--help, -h show this help
--rebuild rebuild the index
--project:file.nim use file.nim as the entry point
In addition, all command line options of Nim that do not affect code generation
are supported.
"""
import strutils, os, parseopt, parseutils
import "../compiler" / [options, commands, modules, sem,
passes, passaux, msgs, nimconf,
extccomp, condsyms,
ast, scriptconfig,
idents, modulegraphs, vm, prefixmatches, lineinfos, cmdlinehelper,
pathutils]
import db_sqlite
proc createDb(db: DbConn) =
db.exec(sql"""
create table if not exists filenames(
id integer primary key,
fullpath varchar(8000) not null
);
""")
db.exec sql"create index if not exists FilenameIx on filenames(fullpath);"
# every sym can have potentially 2 different definitions due to forward
# declarations.
db.exec(sql"""
create table if not exists syms(
id integer primary key,
nimid integer not null,
name varchar(256) not null,
defline integer not null,
defcol integer not null,
deffile integer not null,
deflineB integer not null default 0,
defcolB integer not null default 0,
deffileB integer not null default 0,
foreign key (deffile) references filenames(id),
foreign key (deffileB) references filenames(id)
);
""")
db.exec(sql"""
create table if not exists usages(
id integer primary key,
nimid integer not null,
line integer not null,
col integer not null,
file integer not null,
foreign key (file) references filenames(id),
foreign key (nimid) references syms(nimid)
);
""")
proc toDbFileId*(db: DbConn; conf: ConfigRef; fileIdx: FileIndex): int =
if fileIdx == FileIndex(-1): return -1
let fullpath = toFullPath(conf, fileIdx)
let row = db.getRow(sql"select id from filenames where fullpath = ?", fullpath)
let id = row[0]
if id.len == 0:
result = int db.insertID(sql"insert into filenames(fullpath) values (?)",
fullpath)
else:
result = parseInt(id)
type
FinderRef = ref object of RootObj
db: DbConn
proc writeDef(graph: ModuleGraph; s: PSym; info: TLineInfo) =
let f = FinderRef(graph.backend)
f.db.exec(sql"""insert into syms(nimid, name, defline, defcol, deffile) values (?, ?, ?, ?, ?)""",
s.id, s.name.s, info.line, info.col,
toDbFileId(f.db, graph.config, info.fileIndex))
proc writeDefResolveForward(graph: ModuleGraph; s: PSym; info: TLineInfo) =
let f = FinderRef(graph.backend)
f.db.exec(sql"""update syms set deflineB = ?, defcolB = ?, deffileB = ?
where nimid = ?""", info.line, info.col,
toDbFileId(f.db, graph.config, info.fileIndex), s.id)
proc writeUsage(graph: ModuleGraph; s: PSym; info: TLineInfo) =
let f = FinderRef(graph.backend)
f.db.exec(sql"""insert into usages(nimid, line, col, file) values (?, ?, ?, ?)""",
s.id, info.line, info.col,
toDbFileId(f.db, graph.config, info.fileIndex))
proc performSearch(conf: ConfigRef; dbfile: AbsoluteFile) =
var db = open(connection=string dbfile, user="nim", password="",
database="nim")
let pos = conf.m.trackPos
let fid = toDbFileId(db, conf, pos.fileIndex)
var row = db.getRow(sql"""select max(col) from usages where line = ? and file = ? and ? >= col""",
pos.line, fid, pos.col)
if row.len > 0:
let known = toFullPath(conf, pos.fileIndex)
let nimid = db.getRow(sql"""select nimid from usages where line = ? and file = ? and col = ?""",
pos.line, fid, row[0])
for r in db.rows(sql"""select line, col, filenames.fullpath from usages
inner join filenames on filenames.id = file
where nimid = ?""", nimid):
let line = parseInt(r[0])
let col = parseInt(r[1])
let file = r[2]
if file == known and line == pos.line.int:
discard "don't output the line we already know"
else:
echo file, ":", line, ":", col+1
close(db)
proc setupDb(g: ModuleGraph; dbfile: AbsoluteFile) =
var f = FinderRef()
removeFile(dbfile)
f.db = open(connection=string dbfile, user="nim", password="",
database="nim")
createDb(f.db)
f.db.exec(sql"pragma journal_mode=off")
# This MUST be turned off, otherwise it's way too slow even for testing purposes:
f.db.exec(sql"pragma SYNCHRONOUS=off")
f.db.exec(sql"pragma LOCKING_MODE=exclusive")
g.backend = f
proc mainCommand(graph: ModuleGraph) =
let conf = graph.config
let dbfile = getNimcacheDir(conf) / RelativeFile"nimfind.db"
if not fileExists(dbfile) or optForceFullMake in conf.globalOptions:
clearPasses(graph)
registerPass graph, verbosePass
registerPass graph, semPass
conf.cmd = cmdIdeTools
wantMainModule(conf)
setupDb(graph, dbfile)
graph.onDefinition = writeUsage # writeDef
graph.onDefinitionResolveForward = writeUsage # writeDefResolveForward
graph.onUsage = writeUsage
if not fileExists(conf.projectFull):
quit "cannot find file: " & conf.projectFull.string
add(conf.searchPaths, conf.libpath)
# do not stop after the first error:
conf.errorMax = high(int)
compileProject(graph)
close(FinderRef(graph.backend).db)
performSearch(conf, dbfile)
proc processCmdLine*(pass: TCmdLinePass, cmd: string; conf: ConfigRef) =
var p = parseopt.initOptParser(cmd)
while true:
parseopt.next(p)
case p.kind
of cmdEnd: break
of cmdLongoption, cmdShortOption:
case p.key.normalize
of "help", "h":
stdout.writeline(Usage)
quit()
of "project":
conf.projectName = p.val
of "rebuild":
incl conf.globalOptions, optForceFullMake
else: processSwitch(pass, p, conf)
of cmdArgument:
let info = p.key.split(':')
if info.len == 3:
let (dir, file, ext) = info[0].splitFile()
conf.projectName = findProjectNimFile(conf, dir)
if conf.projectName.len == 0: conf.projectName = info[0]
try:
conf.m.trackPos = newLineInfo(conf, AbsoluteFile info[0],
parseInt(info[1]), parseInt(info[2]))
except ValueError:
quit "invalid command line"
else:
quit "invalid command line"
proc handleCmdLine(cache: IdentCache; conf: ConfigRef) =
let self = NimProg(
suggestMode: true,
processCmdLine: processCmdLine,
mainCommand: mainCommand
)
self.initDefinesProg(conf, "nimfind")
if paramCount() == 0:
stdout.writeline(Usage)
return
self.processCmdLineAndProjectPath(conf)
# Find Nim's prefix dir.
let binaryPath = findExe("nim")
if binaryPath == "":
raise newException(IOError,
"Cannot find Nim standard library: Nim compiler not in PATH")
conf.prefixDir = AbsoluteDir binaryPath.splitPath().head.parentDir()
if not dirExists(conf.prefixDir / RelativeDir"lib"):
conf.prefixDir = AbsoluteDir""
discard self.loadConfigsAndRunMainCommand(cache, conf)
handleCmdline(newIdentCache(), newConfigRef())