mirror of
https://github.com/nim-lang/Nim.git
synced 2026-06-02 18:07:59 +00:00
added first version of a nimfind tool for the poor souls that don't have a good nimsuggest integretation
This commit is contained in:
@@ -63,6 +63,9 @@ type
|
||||
cacheCounters*: Table[string, BiggestInt]
|
||||
cacheTables*: Table[string, BTree[string, PNode]]
|
||||
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
|
||||
PPassContext* = ref TPassContext
|
||||
@@ -78,6 +81,32 @@ type
|
||||
|
||||
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.} =
|
||||
result = g.doStopCompile != nil and g.doStopCompile()
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ import
|
||||
evaltempl, patterns, parampatterns, sempass2, linter, semmacrosanity,
|
||||
lowerings, pluginsupport, plugins/active, rod, lineinfos
|
||||
|
||||
from modulegraphs import ModuleGraph, PPassContext
|
||||
from modulegraphs import ModuleGraph, PPassContext, onUse, onDef, onDefResolveForward
|
||||
|
||||
when defined(nimfix):
|
||||
import nimfix/prettybase
|
||||
@@ -450,7 +450,7 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
|
||||
pushInfoContext(c.config, nOrig.info, sym.detailedInfo)
|
||||
|
||||
markUsed(c.config, n.info, sym, c.graph.usageSym)
|
||||
styleCheckUse(n.info, sym)
|
||||
onUse(n.info, sym)
|
||||
if sym == c.p.owner:
|
||||
globalError(c.config, n.info, "recursive dependency: '$1'" % sym.name.s)
|
||||
|
||||
|
||||
@@ -122,7 +122,7 @@ proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode;
|
||||
if op == nil:
|
||||
op = liftBody(c.c, t, c.kind, c.info)
|
||||
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)
|
||||
result = true
|
||||
|
||||
@@ -132,7 +132,7 @@ proc considerOverloadedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
|
||||
let op = t.destructor
|
||||
if op != nil:
|
||||
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)
|
||||
result = true
|
||||
of attachedAsgn:
|
||||
@@ -143,7 +143,7 @@ proc considerOverloadedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
|
||||
let op = t.deepCopy
|
||||
if op != nil:
|
||||
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)
|
||||
result = true
|
||||
|
||||
|
||||
@@ -454,7 +454,7 @@ proc semResolvedCall(c: PContext, x: TCandidate,
|
||||
assert x.state == csMatch
|
||||
var finalCallee = x.calleeSym
|
||||
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
|
||||
if x.hasFauxMatch:
|
||||
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)
|
||||
newInst.typ.flags.excl tfUnresolved
|
||||
markUsed(c.config, n.info, s, c.graph.usageSym)
|
||||
styleCheckUse(n.info, s)
|
||||
onUse(n.info, s)
|
||||
result = newSymNode(newInst, n.info)
|
||||
|
||||
proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
|
||||
|
||||
@@ -25,7 +25,7 @@ const
|
||||
proc semTemplateExpr(c: PContext, n: PNode, s: PSym,
|
||||
flags: TExprFlags = {}): PNode =
|
||||
markUsed(c.config, n.info, s, c.graph.usageSym)
|
||||
styleCheckUse(n.info, s)
|
||||
onUse(n.info, s)
|
||||
pushInfoContext(c.config, n.info, s.detailedInfo)
|
||||
result = evalTemplate(n, s, getCurrOwner(c), c.config, efFromHlo in 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)
|
||||
if status in {convOK, convNotNeedeed}:
|
||||
markUsed(c.config, n.info, it.sym, c.graph.usageSym)
|
||||
styleCheckUse(n.info, it.sym)
|
||||
onUse(n.info, it.sym)
|
||||
markIndirect(c, it.sym)
|
||||
return it
|
||||
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
|
||||
of skConst:
|
||||
markUsed(c.config, n.info, s, c.graph.usageSym)
|
||||
styleCheckUse(n.info, s)
|
||||
onUse(n.info, s)
|
||||
case skipTypes(s.typ, abstractInst-{tyTypeDesc}).kind
|
||||
of tyNil, tyChar, tyInt..tyInt64, tyFloat..tyFloat128,
|
||||
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
|
||||
(n.kind notin nkCallKinds and s.requiredParams > 0):
|
||||
markUsed(c.config, n.info, s, c.graph.usageSym)
|
||||
styleCheckUse(n.info, s)
|
||||
onUse(n.info, s)
|
||||
result = symChoice(c, n, s, scClosed)
|
||||
else:
|
||||
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
|
||||
sfCustomPragma in sym.flags:
|
||||
markUsed(c.config, n.info, s, c.graph.usageSym)
|
||||
styleCheckUse(n.info, s)
|
||||
onUse(n.info, s)
|
||||
result = symChoice(c, n, s, scClosed)
|
||||
else:
|
||||
result = semTemplateExpr(c, n, s, flags)
|
||||
of skParam:
|
||||
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:
|
||||
# XXX see the hack in sigmatch.nim ...
|
||||
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")
|
||||
|
||||
markUsed(c.config, n.info, s, c.graph.usageSym)
|
||||
styleCheckUse(n.info, s)
|
||||
onUse(n.info, s)
|
||||
result = newSymNode(s, n.info)
|
||||
# We cannot check for access to outer vars for example because it's still
|
||||
# not sure the symbol really ends up being used:
|
||||
# var len = 0 # but won't be called
|
||||
# genericThatUsesLen(x) # marked as taking a closure?
|
||||
of skGenericParam:
|
||||
styleCheckUse(n.info, s)
|
||||
onUse(n.info, s)
|
||||
if s.typ.kind == tyStatic:
|
||||
result = newSymNode(s, n.info)
|
||||
result.typ = s.typ
|
||||
@@ -1116,7 +1116,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
|
||||
return n
|
||||
of skType:
|
||||
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:
|
||||
return s.typ.n
|
||||
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?
|
||||
doAssert f == s
|
||||
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.add makeDeref(newSymNode(p.selfSym))
|
||||
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)
|
||||
# old code, not sure if it's live code:
|
||||
markUsed(c.config, n.info, s, c.graph.usageSym)
|
||||
styleCheckUse(n.info, s)
|
||||
onUse(n.info, s)
|
||||
result = newSymNode(s, n.info)
|
||||
else:
|
||||
markUsed(c.config, n.info, s, c.graph.usageSym)
|
||||
styleCheckUse(n.info, s)
|
||||
onUse(n.info, s)
|
||||
result = newSymNode(s, n.info)
|
||||
|
||||
proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
@@ -1178,7 +1178,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
else:
|
||||
markUsed(c.config, n.sons[1].info, s, c.graph.usageSym)
|
||||
result = semSym(c, n, s, flags)
|
||||
styleCheckUse(n.sons[1].info, s)
|
||||
onUse(n.sons[1].info, s)
|
||||
return
|
||||
|
||||
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.typ = ty
|
||||
markUsed(c.config, n.info, f, c.graph.usageSym)
|
||||
styleCheckUse(n.info, f)
|
||||
onUse(n.info, f)
|
||||
return
|
||||
of tyObject, tyTuple:
|
||||
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):
|
||||
# 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)
|
||||
styleCheckUse(n.sons[1].info, f)
|
||||
onUse(n.sons[1].info, f)
|
||||
n.sons[0] = makeDeref(n.sons[0])
|
||||
n.sons[1] = newSymNode(f) # we now have the correct field
|
||||
n.typ = f.typ
|
||||
@@ -1286,7 +1286,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
f = getSymFromList(ty.n, i)
|
||||
if f != nil:
|
||||
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[1] = newSymNode(f)
|
||||
n.typ = f.typ
|
||||
@@ -1758,7 +1758,7 @@ proc semExpandToAst(c: PContext, n: PNode): PNode =
|
||||
|
||||
macroCall.sons[0] = newSymNode(expandedSym, macroCall.info)
|
||||
markUsed(c.config, n.info, expandedSym, c.graph.usageSym)
|
||||
styleCheckUse(n.info, expandedSym)
|
||||
onUse(n.info, expandedSym)
|
||||
|
||||
if isCallExpr(macroCall):
|
||||
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
|
||||
macroCall.sons[0] = newSymNode(cand, info)
|
||||
markUsed(c.config, info, cand, c.graph.usageSym)
|
||||
styleCheckUse(info, cand)
|
||||
onUse(info, cand)
|
||||
|
||||
# we just perform overloading resolution here:
|
||||
#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)
|
||||
suggestSym(c.config, n.sons[0].info, labl, c.graph.usageSym)
|
||||
styleCheckDef(c.config, labl)
|
||||
onDef(n[0].info, labl)
|
||||
n.sons[1] = semExpr(c, n.sons[1], flags)
|
||||
n.typ = n.sons[1].typ
|
||||
if isEmptyType(n.typ): n.kind = nkBlockStmt
|
||||
|
||||
@@ -76,14 +76,14 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
|
||||
result = symChoice(c, n, s, scOpen)
|
||||
of skTemplate:
|
||||
if macroToExpandSym(s):
|
||||
styleCheckUse(n.info, s)
|
||||
onUse(n.info, s)
|
||||
result = semTemplateExpr(c, n, s, {efNoSemCheck})
|
||||
result = semGenericStmt(c, result, {}, ctx)
|
||||
else:
|
||||
result = symChoice(c, n, s, scOpen)
|
||||
of skMacro:
|
||||
if macroToExpandSym(s):
|
||||
styleCheckUse(n.info, s)
|
||||
onUse(n.info, s)
|
||||
result = semMacroExpr(c, n, n, s, {efNoSemCheck})
|
||||
result = semGenericStmt(c, result, {}, ctx)
|
||||
else:
|
||||
@@ -96,20 +96,20 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
|
||||
result = n
|
||||
else:
|
||||
result = newSymNodeTypeDesc(s, n.info)
|
||||
styleCheckUse(n.info, s)
|
||||
onUse(n.info, s)
|
||||
of skParam:
|
||||
result = n
|
||||
styleCheckUse(n.info, s)
|
||||
onUse(n.info, s)
|
||||
of skType:
|
||||
if (s.typ != nil) and
|
||||
(s.typ.flags * {tfGenericTypeParam, tfImplicitTypeParam} == {}):
|
||||
result = newSymNodeTypeDesc(s, n.info)
|
||||
else:
|
||||
result = n
|
||||
styleCheckUse(n.info, s)
|
||||
onUse(n.info, s)
|
||||
else:
|
||||
result = newSymNode(s, n.info)
|
||||
styleCheckUse(n.info, s)
|
||||
onUse(n.info, s)
|
||||
|
||||
proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags,
|
||||
ctx: var GenericCtx): PNode =
|
||||
@@ -172,6 +172,7 @@ proc addTempDecl(c: PContext; n: PNode; kind: TSymKind) =
|
||||
let s = newSymS(skUnknown, getIdentNode(c, n), c)
|
||||
addPrelimDecl(c, s)
|
||||
styleCheckDef(c.config, n.info, s, kind)
|
||||
onDef(n.info, s)
|
||||
|
||||
proc semGenericStmt(c: PContext, n: PNode,
|
||||
flags: TSemGenericFlags, ctx: var GenericCtx): PNode =
|
||||
@@ -230,7 +231,7 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||
case s.kind
|
||||
of skMacro:
|
||||
if macroToExpand(s) and sc.safeLen <= 1:
|
||||
styleCheckUse(fn.info, s)
|
||||
onUse(fn.info, s)
|
||||
result = semMacroExpr(c, n, n, s, {efNoSemCheck})
|
||||
result = semGenericStmt(c, result, flags, ctx)
|
||||
else:
|
||||
@@ -239,7 +240,7 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||
mixinContext = true
|
||||
of skTemplate:
|
||||
if macroToExpand(s) and sc.safeLen <= 1:
|
||||
styleCheckUse(fn.info, s)
|
||||
onUse(fn.info, s)
|
||||
result = semTemplateExpr(c, n, s, {efNoSemCheck})
|
||||
result = semGenericStmt(c, result, flags, ctx)
|
||||
else:
|
||||
@@ -262,17 +263,17 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||
inc first
|
||||
of skGenericParam:
|
||||
result.sons[0] = newSymNodeTypeDesc(s, fn.info)
|
||||
styleCheckUse(fn.info, s)
|
||||
onUse(fn.info, s)
|
||||
first = 1
|
||||
of skType:
|
||||
# bad hack for generics:
|
||||
if (s.typ != nil) and (s.typ.kind != tyGenericParam):
|
||||
result.sons[0] = newSymNodeTypeDesc(s, fn.info)
|
||||
styleCheckUse(fn.info, s)
|
||||
onUse(fn.info, s)
|
||||
first = 1
|
||||
else:
|
||||
result.sons[0] = newSymNode(s, fn.info)
|
||||
styleCheckUse(fn.info, s)
|
||||
onUse(fn.info, s)
|
||||
first = 1
|
||||
elif fn.kind == nkDotExpr:
|
||||
result.sons[0] = fuzzyLookup(c, fn, flags, ctx, mixinContext)
|
||||
|
||||
@@ -65,7 +65,7 @@ proc semBreakOrContinue(c: PContext, n: PNode): PNode =
|
||||
incl(s.flags, sfUsed)
|
||||
n.sons[0] = x
|
||||
suggestSym(c.config, x.info, s, c.graph.usageSym)
|
||||
styleCheckUse(x.info, s)
|
||||
onUse(x.info, s)
|
||||
else:
|
||||
localError(c.config, n.info, errInvalidControlFlowX % s.name.s)
|
||||
else:
|
||||
@@ -363,6 +363,7 @@ proc semUsing(c: PContext; n: PNode): PNode =
|
||||
for j in countup(0, length-3):
|
||||
let v = semIdentDef(c, a.sons[j], skParam)
|
||||
styleCheckDef(c.config, v)
|
||||
onDef(a[j].info, v)
|
||||
v.typ = typ
|
||||
strTableIncl(c.signatures, v)
|
||||
else:
|
||||
@@ -494,6 +495,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
||||
continue
|
||||
var v = semIdentDef(c, a.sons[j], symkind)
|
||||
styleCheckDef(c.config, v)
|
||||
onDef(a[j].info, v)
|
||||
if sfGenSym notin v.flags and not isDiscardUnderscore(v):
|
||||
addInterfaceDecl(c, v)
|
||||
when oKeepVariableNames:
|
||||
@@ -548,6 +550,7 @@ proc semConst(c: PContext, n: PNode): PNode =
|
||||
checkSonsLen(a, 3, c.config)
|
||||
var v = semIdentDef(c, a.sons[0], skConst)
|
||||
styleCheckDef(c.config, v)
|
||||
onDef(a[0].info, v)
|
||||
var typ: PType = 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
|
||||
result = newSymG(skForVar, m, c)
|
||||
styleCheckDef(c.config, result)
|
||||
onDef(n.info, result)
|
||||
if n.kind == nkPragmaExpr:
|
||||
pragma(c, result, n.sons[1], forVarPragmas)
|
||||
|
||||
@@ -696,7 +700,7 @@ proc handleCaseStmtMacro(c: PContext; n: PNode): PNode =
|
||||
if r.state == csMatch:
|
||||
var match = r.calleeSym
|
||||
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]':
|
||||
r.call.sons[1] = n
|
||||
@@ -880,6 +884,7 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) =
|
||||
if typsym.isNil:
|
||||
s = semIdentDef(c, name[1], skType)
|
||||
styleCheckDef(c.config, s)
|
||||
onDef(name[1].info, s)
|
||||
s.typ = newTypeS(tyObject, c)
|
||||
s.typ.sym = s
|
||||
s.flags.incl sfForward
|
||||
@@ -894,6 +899,7 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) =
|
||||
else:
|
||||
s = semIdentDef(c, name, skType)
|
||||
styleCheckDef(c.config, s)
|
||||
onDef(name.info, s)
|
||||
s.typ = newTypeS(tyForward, c)
|
||||
s.typ.sym = s # process pragmas:
|
||||
if name.kind == nkPragmaExpr:
|
||||
@@ -1625,6 +1631,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||
else:
|
||||
implicitPragmas(c, s, n, validPragmas)
|
||||
styleCheckDef(c.config, s)
|
||||
onDef(n[namePos].info, s)
|
||||
else:
|
||||
if n.sons[pragmasPos].kind != nkEmpty:
|
||||
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 %
|
||||
("'" & proto.name.s & "' from " & c.config$proto.info))
|
||||
styleCheckDef(c.config, s)
|
||||
onDefResolveForward(n[namePos].info, proto)
|
||||
if sfForward notin proto.flags and proto.magic == mNone:
|
||||
wrongRedefinition(c, n.info, proto.name.s, proto.info)
|
||||
excl(proto.flags, sfForward)
|
||||
|
||||
@@ -160,7 +160,7 @@ proc onlyReplaceParams(c: var TemplCtx, n: PNode): PNode =
|
||||
if s.owner == c.owner and s.kind == skParam:
|
||||
incl(s.flags, sfUsed)
|
||||
result = newSymNode(s, n.info)
|
||||
styleCheckUse(n.info, s)
|
||||
onUse(n.info, s)
|
||||
else:
|
||||
for i in 0 ..< n.safeLen:
|
||||
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.
|
||||
let s = localSearchInScope(c.c, considerQuotedIdent(c.c, ident))
|
||||
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))
|
||||
elif not (n.kind == nkSym and sfGenSym in n.sym.flags):
|
||||
let local = newGenSym(k, ident, c)
|
||||
addPrelimDecl(c.c, local)
|
||||
styleCheckDef(c.c.config, n.info, local)
|
||||
onDef(n.info, local)
|
||||
replaceIdentBySym(c.c, n, newSymNode(local, n.info))
|
||||
else:
|
||||
replaceIdentBySym(c.c, n, ident)
|
||||
|
||||
proc semTemplSymbol(c: PContext, n: PNode, s: PSym): PNode =
|
||||
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.
|
||||
case s.kind
|
||||
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):
|
||||
incl(s.flags, sfUsed)
|
||||
result = newSymNode(s, n.info)
|
||||
styleCheckUse(n.info, s)
|
||||
onUse(n.info, s)
|
||||
else:
|
||||
for i in countup(0, safeLen(n) - 1):
|
||||
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
|
||||
addPrelimDecl(c.c, s)
|
||||
styleCheckDef(c.c.config, n.info, s)
|
||||
onDef(n.info, s)
|
||||
n.sons[namePos] = newSymNode(s, n.sons[namePos].info)
|
||||
else:
|
||||
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:
|
||||
incl(s.flags, sfUsed)
|
||||
result = newSymNode(s, n.info)
|
||||
styleCheckUse(n.info, s)
|
||||
onUse(n.info, s)
|
||||
elif contains(c.toBind, s.id):
|
||||
result = symChoice(c.c, n, s, scClosed)
|
||||
elif contains(c.toMixin, s.name.id):
|
||||
@@ -324,7 +326,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
|
||||
# var yz: T
|
||||
incl(s.flags, sfUsed)
|
||||
result = newSymNode(s, n.info)
|
||||
styleCheckUse(n.info, s)
|
||||
onUse(n.info, s)
|
||||
else:
|
||||
result = semTemplSymbol(c.c, n, s)
|
||||
of nkBind:
|
||||
@@ -382,6 +384,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
|
||||
let s = newGenSym(skLabel, n.sons[0], c)
|
||||
addPrelimDecl(c.c, s)
|
||||
styleCheckDef(c.c.config, s)
|
||||
onDef(n[0].info, s)
|
||||
n.sons[0] = newSymNode(s, n.sons[0].info)
|
||||
n.sons[1] = semTemplBody(c, n.sons[1])
|
||||
closeScope(c)
|
||||
@@ -505,7 +508,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
|
||||
if s.owner == c.owner and s.kind == skParam and
|
||||
n.kind == nkAccQuoted and n.len == 1:
|
||||
incl(s.flags, sfUsed)
|
||||
styleCheckUse(n.info, s)
|
||||
onUse(n.info, s)
|
||||
return newSymNode(s, n.info)
|
||||
elif contains(c.toBind, s.id):
|
||||
return symChoice(c.c, n, s, scClosed)
|
||||
@@ -553,6 +556,7 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
|
||||
else:
|
||||
s = semIdentVis(c, skTemplate, n.sons[0], {})
|
||||
styleCheckDef(c.config, s)
|
||||
onDef(n[0].info, s)
|
||||
# check parameter list:
|
||||
#s.scope = c.currentScope
|
||||
pushOwner(c, s)
|
||||
@@ -635,7 +639,7 @@ proc semPatternBody(c: var TemplCtx, n: PNode): PNode =
|
||||
# semtypes.addParamOrResult). Within the pattern we have to ensure
|
||||
# to use the param with the proper type though:
|
||||
incl(s.flags, sfUsed)
|
||||
styleCheckUse(n.info, s)
|
||||
onUse(n.info, s)
|
||||
let x = c.owner.typ.n.sons[s.position+1].sym
|
||||
assert x.name == s.name
|
||||
result = newSymNode(x, n.info)
|
||||
|
||||
@@ -122,6 +122,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
|
||||
if not isPure: strTableAdd(c.module.tab, e)
|
||||
addSon(result.n, newSymNode(e))
|
||||
styleCheckDef(c.config, e)
|
||||
onDef(e.info, e)
|
||||
if sfGenSym notin e.flags:
|
||||
if not isPure: addDecl(c, e)
|
||||
else: importPureEnumField(c, e)
|
||||
@@ -377,7 +378,7 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
|
||||
result = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared})
|
||||
if result != nil:
|
||||
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:
|
||||
# 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))
|
||||
addSonSkipIntLit(result, typ)
|
||||
styleCheckDef(c.config, a.sons[j].info, field)
|
||||
onDef(field.info, field)
|
||||
if result.n.len == 0: result.n = nil
|
||||
|
||||
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
|
||||
for i in countup(0, sonsLen(n)-3):
|
||||
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)
|
||||
f.typ = typ
|
||||
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))
|
||||
else: addSon(a, newSymNode(f))
|
||||
styleCheckDef(c.config, f)
|
||||
onDef(f.info, f)
|
||||
if a.kind != nkEmpty: addSon(father, a)
|
||||
of nkSym:
|
||||
# This branch only valid during generic object
|
||||
@@ -988,7 +990,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
||||
|
||||
of tyGenericParam:
|
||||
markUsed(c.config, info, paramType.sym, c.graph.usageSym)
|
||||
styleCheckUse(info, paramType.sym)
|
||||
onUse(info, paramType.sym)
|
||||
if tfWildcard in paramType.flags:
|
||||
paramType.flags.excl tfWildcard
|
||||
paramType.sym.kind = skType
|
||||
@@ -1110,6 +1112,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
||||
rawAddSon(result, finalType)
|
||||
addParamOrResult(c, arg, kind)
|
||||
styleCheckDef(c.config, a.sons[j].info, arg)
|
||||
onDef(a[j].info, arg)
|
||||
|
||||
var r: PType
|
||||
if n.sons[0].kind != nkEmpty:
|
||||
@@ -1637,7 +1640,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||
assignType(prev, t)
|
||||
result = prev
|
||||
markUsed(c.config, n.info, n.sym, c.graph.usageSym)
|
||||
styleCheckUse(n.info, n.sym)
|
||||
onUse(n.info, n.sym)
|
||||
else:
|
||||
if s.kind != skError: localError(c.config, n.info, errTypeExpected)
|
||||
result = newOrPrevType(tyError, prev, c)
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
import
|
||||
intsets, ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst,
|
||||
magicsys, condsyms, idents, lexer, options, parampatterns, strutils, trees,
|
||||
linter, lineinfos
|
||||
linter, lineinfos, modulegraphs
|
||||
|
||||
when (defined(booting) or defined(nimsuggest)) and not defined(leanCompiler):
|
||||
import docgen
|
||||
@@ -2149,7 +2149,7 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
|
||||
else:
|
||||
# only one valid interpretation found:
|
||||
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],
|
||||
argOrig)
|
||||
when false:
|
||||
|
||||
228
tools/nimfind.nim
Normal file
228
tools/nimfind.nim
Normal 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())
|
||||
Reference in New Issue
Block a user