[feature] detect unused imports
This commit is contained in:
parent
44d80dd863
commit
4137a4dbf3
12 changed files with 62 additions and 33 deletions
|
|
@ -167,6 +167,7 @@ proc myImportModule(c: PContext, n: PNode; importStmtResult: PNode): PSym =
|
||||||
message(c.config, n.info, warnDeprecated, result.name.s & " is deprecated")
|
message(c.config, n.info, warnDeprecated, result.name.s & " is deprecated")
|
||||||
suggestSym(c.config, n.info, result, c.graph.usageSym, false)
|
suggestSym(c.config, n.info, result, c.graph.usageSym, false)
|
||||||
importStmtResult.add newSymNode(result, n.info)
|
importStmtResult.add newSymNode(result, n.info)
|
||||||
|
c.unusedImports.add((result, n.info))
|
||||||
#newStrNode(toFullPath(c.config, f), n.info)
|
#newStrNode(toFullPath(c.config, f), n.info)
|
||||||
|
|
||||||
proc transformImportAs(c: PContext; n: PNode): PNode =
|
proc transformImportAs(c: PContext; n: PNode): PNode =
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,8 @@ type
|
||||||
warnUninit, warnGcMem, warnDestructor, warnLockLevel, warnResultShadowed,
|
warnUninit, warnGcMem, warnDestructor, warnLockLevel, warnResultShadowed,
|
||||||
warnInconsistentSpacing, warnCaseTransition, warnUser,
|
warnInconsistentSpacing, warnCaseTransition, warnUser,
|
||||||
hintSuccess, hintSuccessX, hintCC,
|
hintSuccess, hintSuccessX, hintCC,
|
||||||
hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded,
|
hintLineTooLong, hintXDeclaredButNotUsed, hintUnusedModuleX,
|
||||||
|
hintConvToBaseNotNeeded,
|
||||||
hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled,
|
hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled,
|
||||||
hintProcessing, hintCodeBegin, hintCodeEnd, hintConf, hintPath,
|
hintProcessing, hintCodeBegin, hintCodeEnd, hintConf, hintPath,
|
||||||
hintConditionAlwaysTrue, hintConditionAlwaysFalse, hintName, hintPattern,
|
hintConditionAlwaysTrue, hintConditionAlwaysFalse, hintName, hintPattern,
|
||||||
|
|
@ -97,6 +98,7 @@ const
|
||||||
hintCC: "CC: \'$1\'", # unused
|
hintCC: "CC: \'$1\'", # unused
|
||||||
hintLineTooLong: "line too long",
|
hintLineTooLong: "line too long",
|
||||||
hintXDeclaredButNotUsed: "'$1' is declared but not used",
|
hintXDeclaredButNotUsed: "'$1' is declared but not used",
|
||||||
|
hintUnusedModuleX: "unused module: '$1'",
|
||||||
hintConvToBaseNotNeeded: "conversion to base object is not needed",
|
hintConvToBaseNotNeeded: "conversion to base object is not needed",
|
||||||
hintConvFromXtoItselfNotNeeded: "conversion from $1 to itself is pointless",
|
hintConvFromXtoItselfNotNeeded: "conversion from $1 to itself is pointless",
|
||||||
hintExprAlwaysX: "expression evaluates always to '$1'",
|
hintExprAlwaysX: "expression evaluates always to '$1'",
|
||||||
|
|
@ -140,7 +142,8 @@ const
|
||||||
|
|
||||||
HintsToStr* = [
|
HintsToStr* = [
|
||||||
"Success", "SuccessX", "CC", "LineTooLong",
|
"Success", "SuccessX", "CC", "LineTooLong",
|
||||||
"XDeclaredButNotUsed", "ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded",
|
"XDeclaredButNotUsed", "UnusedModule",
|
||||||
|
"ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded",
|
||||||
"ExprAlwaysX", "QuitCalled", "Processing", "CodeBegin", "CodeEnd", "Conf",
|
"ExprAlwaysX", "QuitCalled", "Processing", "CodeBegin", "CodeEnd", "Conf",
|
||||||
"Path", "CondTrue", "CondFalse", "Name", "Pattern", "Exec", "Link", "Dependency",
|
"Path", "CondTrue", "CondFalse", "Name", "Pattern", "Exec", "Link", "Dependency",
|
||||||
"Source", "Performance", "StackTrace", "GCStats", "GlobalVar", "ExpandMacro",
|
"Source", "Performance", "StackTrace", "GCStats", "GlobalVar", "ExpandMacro",
|
||||||
|
|
|
||||||
|
|
@ -296,7 +296,7 @@ proc applyRule*(c: PContext, s: PSym, n: PNode): PNode =
|
||||||
# constraint not fulfilled:
|
# constraint not fulfilled:
|
||||||
if not ok: return nil
|
if not ok: return nil
|
||||||
|
|
||||||
markUsed(c.config, n.info, s, c.graph.usageSym)
|
markUsed(c, n.info, s, c.graph.usageSym)
|
||||||
if ctx.subMatch:
|
if ctx.subMatch:
|
||||||
assert m.len == 3
|
assert m.len == 3
|
||||||
m.sons[1] = result
|
m.sons[1] = result
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
let info = getCallLineInfo(n)
|
let info = getCallLineInfo(n)
|
||||||
markUsed(c.config, info, sym, c.graph.usageSym)
|
markUsed(c, info, sym, c.graph.usageSym)
|
||||||
onUse(info, sym)
|
onUse(info, sym)
|
||||||
if sym == c.p.owner:
|
if sym == c.p.owner:
|
||||||
globalError(c.config, info, "recursive dependency: '$1'" % sym.name.s)
|
globalError(c.config, info, "recursive dependency: '$1'" % sym.name.s)
|
||||||
|
|
@ -618,12 +618,17 @@ proc myProcess(context: PPassContext, n: PNode): PNode =
|
||||||
#if c.config.cmd == cmdIdeTools: findSuggest(c, n)
|
#if c.config.cmd == cmdIdeTools: findSuggest(c, n)
|
||||||
rod.storeNode(c.graph, c.module, result)
|
rod.storeNode(c.graph, c.module, result)
|
||||||
|
|
||||||
|
proc reportUnusedModules(c: PContext) =
|
||||||
|
for i in 0..high(c.unusedImports):
|
||||||
|
message(c.config, c.unusedImports[i][1], hintUnusedModuleX, c.unusedImports[i][0].name.s)
|
||||||
|
|
||||||
proc myClose(graph: ModuleGraph; context: PPassContext, n: PNode): PNode =
|
proc myClose(graph: ModuleGraph; context: PPassContext, n: PNode): PNode =
|
||||||
var c = PContext(context)
|
var c = PContext(context)
|
||||||
if c.config.cmd == cmdIdeTools and not c.suggestionsMade:
|
if c.config.cmd == cmdIdeTools and not c.suggestionsMade:
|
||||||
suggestSentinel(c)
|
suggestSentinel(c)
|
||||||
closeScope(c) # close module's scope
|
closeScope(c) # close module's scope
|
||||||
rawCloseScope(c) # imported symbols; don't check for unused ones!
|
rawCloseScope(c) # imported symbols; don't check for unused ones!
|
||||||
|
reportUnusedModules(c)
|
||||||
result = newNode(nkStmtList)
|
result = newNode(nkStmtList)
|
||||||
if n != nil:
|
if n != nil:
|
||||||
internalError(c.config, n.info, "n is not nil") #result := n;
|
internalError(c.config, n.info, "n is not nil") #result := n;
|
||||||
|
|
|
||||||
|
|
@ -474,7 +474,7 @@ proc semResolvedCall(c: PContext, x: TCandidate,
|
||||||
assert x.state == csMatch
|
assert x.state == csMatch
|
||||||
var finalCallee = x.calleeSym
|
var finalCallee = x.calleeSym
|
||||||
let info = getCallLineInfo(n)
|
let info = getCallLineInfo(n)
|
||||||
markUsed(c.config, info, finalCallee, c.graph.usageSym)
|
markUsed(c, info, finalCallee, c.graph.usageSym)
|
||||||
onUse(info, finalCallee)
|
onUse(info, finalCallee)
|
||||||
assert finalCallee.ast != nil
|
assert finalCallee.ast != nil
|
||||||
if x.hasFauxMatch:
|
if x.hasFauxMatch:
|
||||||
|
|
@ -584,7 +584,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
|
||||||
let info = getCallLineInfo(n)
|
let info = getCallLineInfo(n)
|
||||||
markUsed(c.config, info, s, c.graph.usageSym)
|
markUsed(c, info, s, c.graph.usageSym)
|
||||||
onUse(info, s)
|
onUse(info, s)
|
||||||
result = newSymNode(newInst, info)
|
result = newSymNode(newInst, info)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,8 @@ type
|
||||||
TExprFlags* = set[TExprFlag]
|
TExprFlags* = set[TExprFlag]
|
||||||
|
|
||||||
PContext* = ref TContext
|
PContext* = ref TContext
|
||||||
TContext* = object of TPassContext # a context represents a module
|
TContext* = object of TPassContext # a context represents the module
|
||||||
|
# that is currently being compiled
|
||||||
enforceVoidContext*: PType
|
enforceVoidContext*: PType
|
||||||
module*: PSym # the module sym belonging to the context
|
module*: PSym # the module sym belonging to the context
|
||||||
currentScope*: PScope # current scope
|
currentScope*: PScope # current scope
|
||||||
|
|
@ -139,6 +140,7 @@ type
|
||||||
# the generic type has been constructed completely. See
|
# the generic type has been constructed completely. See
|
||||||
# tests/destructor/topttree.nim for an example that
|
# tests/destructor/topttree.nim for an example that
|
||||||
# would otherwise fail.
|
# would otherwise fail.
|
||||||
|
unusedImports*: seq[(PSym, TLineInfo)]
|
||||||
|
|
||||||
template config*(c: PContext): ConfigRef = c.graph.config
|
template config*(c: PContext): ConfigRef = c.graph.config
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 =
|
||||||
let info = getCallLineInfo(n)
|
let info = getCallLineInfo(n)
|
||||||
markUsed(c.config, info, s, c.graph.usageSym)
|
markUsed(c, info, s, c.graph.usageSym)
|
||||||
onUse(info, s)
|
onUse(info, s)
|
||||||
# Note: This is n.info on purpose. It prevents template from creating an info
|
# Note: This is n.info on purpose. It prevents template from creating an info
|
||||||
# context when called from an another template
|
# context when called from an another template
|
||||||
|
|
@ -305,7 +305,7 @@ proc semConv(c: PContext, n: PNode): PNode =
|
||||||
let it = op.sons[i]
|
let it = op.sons[i]
|
||||||
let status = checkConvertible(c, result.typ, it)
|
let status = checkConvertible(c, result.typ, it)
|
||||||
if status in {convOK, convNotNeedeed}:
|
if status in {convOK, convNotNeedeed}:
|
||||||
markUsed(c.config, n.info, it.sym, c.graph.usageSym)
|
markUsed(c, n.info, it.sym, c.graph.usageSym)
|
||||||
onUse(n.info, it.sym)
|
onUse(n.info, it.sym)
|
||||||
markIndirect(c, it.sym)
|
markIndirect(c, it.sym)
|
||||||
return it
|
return it
|
||||||
|
|
@ -1106,7 +1106,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
|
||||||
let s = getGenSym(c, sym)
|
let s = getGenSym(c, sym)
|
||||||
case s.kind
|
case s.kind
|
||||||
of skConst:
|
of skConst:
|
||||||
markUsed(c.config, n.info, s, c.graph.usageSym)
|
markUsed(c, n.info, s, c.graph.usageSym)
|
||||||
onUse(n.info, s)
|
onUse(n.info, s)
|
||||||
let typ = skipTypes(s.typ, abstractInst-{tyTypeDesc})
|
let typ = skipTypes(s.typ, abstractInst-{tyTypeDesc})
|
||||||
case typ.kind
|
case typ.kind
|
||||||
|
|
@ -1138,7 +1138,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
|
||||||
of skMacro:
|
of skMacro:
|
||||||
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, n.info, s, c.graph.usageSym)
|
||||||
onUse(n.info, s)
|
onUse(n.info, s)
|
||||||
result = symChoice(c, n, s, scClosed)
|
result = symChoice(c, n, s, scClosed)
|
||||||
else:
|
else:
|
||||||
|
|
@ -1148,13 +1148,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:
|
||||||
let info = getCallLineInfo(n)
|
let info = getCallLineInfo(n)
|
||||||
markUsed(c.config, info, s, c.graph.usageSym)
|
markUsed(c, info, s, c.graph.usageSym)
|
||||||
onUse(info, s)
|
onUse(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, n.info, s, c.graph.usageSym)
|
||||||
onUse(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 ...
|
||||||
|
|
@ -1178,7 +1178,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
|
||||||
if s.magic == mNimvm:
|
if s.magic == mNimvm:
|
||||||
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, n.info, s, c.graph.usageSym)
|
||||||
onUse(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
|
||||||
|
|
@ -1196,7 +1196,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
|
||||||
n.typ = s.typ
|
n.typ = s.typ
|
||||||
return n
|
return n
|
||||||
of skType:
|
of skType:
|
||||||
markUsed(c.config, n.info, s, c.graph.usageSym)
|
markUsed(c, n.info, s, c.graph.usageSym)
|
||||||
onUse(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
|
||||||
|
|
@ -1218,7 +1218,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
|
||||||
if f != nil and fieldVisible(c, f):
|
if f != nil and 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?
|
||||||
doAssert f == s
|
doAssert f == s
|
||||||
markUsed(c.config, n.info, f, c.graph.usageSym)
|
markUsed(c, n.info, f, c.graph.usageSym)
|
||||||
onUse(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))
|
||||||
|
|
@ -1231,12 +1231,12 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
|
||||||
if ty.sons[0] == nil: break
|
if ty.sons[0] == nil: break
|
||||||
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, n.info, s, c.graph.usageSym)
|
||||||
onUse(n.info, s)
|
onUse(n.info, s)
|
||||||
result = newSymNode(s, n.info)
|
result = newSymNode(s, n.info)
|
||||||
else:
|
else:
|
||||||
let info = getCallLineInfo(n)
|
let info = getCallLineInfo(n)
|
||||||
markUsed(c.config, info, s, c.graph.usageSym)
|
markUsed(c, info, s, c.graph.usageSym)
|
||||||
onUse(info, s)
|
onUse(info, s)
|
||||||
result = newSymNode(s, info)
|
result = newSymNode(s, info)
|
||||||
|
|
||||||
|
|
@ -1258,7 +1258,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
result = symChoice(c, n, s, scClosed)
|
result = symChoice(c, n, s, scClosed)
|
||||||
if result.kind == nkSym: result = semSym(c, n, s, flags)
|
if result.kind == nkSym: result = semSym(c, n, s, flags)
|
||||||
else:
|
else:
|
||||||
markUsed(c.config, n.sons[1].info, s, c.graph.usageSym)
|
markUsed(c, n.sons[1].info, s, c.graph.usageSym)
|
||||||
result = semSym(c, n, s, flags)
|
result = semSym(c, n, s, flags)
|
||||||
onUse(n.sons[1].info, s)
|
onUse(n.sons[1].info, s)
|
||||||
return
|
return
|
||||||
|
|
@ -1322,7 +1322,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
result = newSymNode(f)
|
result = newSymNode(f)
|
||||||
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, n.info, f, c.graph.usageSym)
|
||||||
onUse(n.info, f)
|
onUse(n.info, f)
|
||||||
return
|
return
|
||||||
of tyObject, tyTuple:
|
of tyObject, tyTuple:
|
||||||
|
|
@ -1357,7 +1357,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
else: true
|
else: true
|
||||||
if not visibilityCheckNeeded or fieldVisible(c, f):
|
if not visibilityCheckNeeded or 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, n.sons[1].info, f, c.graph.usageSym)
|
||||||
onUse(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
|
||||||
|
|
@ -1371,7 +1371,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
elif ty.kind == tyTuple and ty.n != nil:
|
elif ty.kind == tyTuple and ty.n != nil:
|
||||||
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, n.sons[1].info, f, c.graph.usageSym)
|
||||||
onUse(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)
|
||||||
|
|
@ -1902,7 +1902,7 @@ proc semExpandToAst(c: PContext, n: PNode): PNode =
|
||||||
if expandedSym.kind == skError: return n
|
if expandedSym.kind == skError: return n
|
||||||
|
|
||||||
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, n.info, expandedSym, c.graph.usageSym)
|
||||||
onUse(n.info, expandedSym)
|
onUse(n.info, expandedSym)
|
||||||
|
|
||||||
if isCallExpr(macroCall):
|
if isCallExpr(macroCall):
|
||||||
|
|
@ -1927,7 +1927,7 @@ proc semExpandToAst(c: PContext, n: PNode): PNode =
|
||||||
else:
|
else:
|
||||||
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, info, cand, c.graph.usageSym)
|
||||||
onUse(info, cand)
|
onUse(info, cand)
|
||||||
|
|
||||||
# we just perform overloading resolution here:
|
# we just perform overloading resolution here:
|
||||||
|
|
@ -2453,6 +2453,7 @@ proc semExportExcept(c: PContext, n: PNode): PNode =
|
||||||
s.name.id notin exceptSet:
|
s.name.id notin exceptSet:
|
||||||
strTableAdd(c.module.tab, s)
|
strTableAdd(c.module.tab, s)
|
||||||
result.add newSymNode(s, n.info)
|
result.add newSymNode(s, n.info)
|
||||||
|
markUsed(c, n.info, s, c.graph.usageSym)
|
||||||
s = nextIter(i, exported.tab)
|
s = nextIter(i, exported.tab)
|
||||||
|
|
||||||
proc semExport(c: PContext, n: PNode): PNode =
|
proc semExport(c: PContext, n: PNode): PNode =
|
||||||
|
|
@ -2473,6 +2474,7 @@ proc semExport(c: PContext, n: PNode): PNode =
|
||||||
strTableAdd(c.module.tab, it)
|
strTableAdd(c.module.tab, it)
|
||||||
result.add newSymNode(it, a.info)
|
result.add newSymNode(it, a.info)
|
||||||
it = nextIter(ti, s.tab)
|
it = nextIter(ti, s.tab)
|
||||||
|
markUsed(c, n.info, s, c.graph.usageSym)
|
||||||
else:
|
else:
|
||||||
while s != nil:
|
while s != nil:
|
||||||
if s.kind == skEnumField:
|
if s.kind == skEnumField:
|
||||||
|
|
@ -2481,6 +2483,7 @@ proc semExport(c: PContext, n: PNode): PNode =
|
||||||
if s.kind in ExportableSymKinds+{skModule}:
|
if s.kind in ExportableSymKinds+{skModule}:
|
||||||
result.add(newSymNode(s, a.info))
|
result.add(newSymNode(s, a.info))
|
||||||
strTableAdd(c.module.tab, s)
|
strTableAdd(c.module.tab, s)
|
||||||
|
markUsed(c, n.info, s, c.graph.usageSym)
|
||||||
s = nextOverloadIter(o, c, a)
|
s = nextOverloadIter(o, c, a)
|
||||||
|
|
||||||
proc semTupleConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
proc semTupleConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
|
|
|
||||||
|
|
@ -812,7 +812,7 @@ proc handleCaseStmtMacro(c: PContext; n: PNode): PNode =
|
||||||
errors, false)
|
errors, false)
|
||||||
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, n[0].info, match, c.graph.usageSym)
|
||||||
onUse(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]':
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@ proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule): PNode =
|
||||||
# (s.kind notin routineKinds or s.magic != mNone):
|
# (s.kind notin routineKinds or s.magic != mNone):
|
||||||
# for instance 'nextTry' is both in tables.nim and astalgo.nim ...
|
# for instance 'nextTry' is both in tables.nim and astalgo.nim ...
|
||||||
result = newSymNode(s, info)
|
result = newSymNode(s, info)
|
||||||
markUsed(c.config, info, s, c.graph.usageSym)
|
markUsed(c, info, s, c.graph.usageSym)
|
||||||
onUse(info, s)
|
onUse(info, s)
|
||||||
else:
|
else:
|
||||||
# semantic checking requires a type; ``fitNode`` deals with it
|
# semantic checking requires a type; ``fitNode`` deals with it
|
||||||
|
|
|
||||||
|
|
@ -353,7 +353,7 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
|
||||||
if result.isNil:
|
if result.isNil:
|
||||||
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, n.info, result, c.graph.usageSym)
|
||||||
onUse(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:
|
||||||
|
|
@ -1063,7 +1063,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
||||||
result = addImplicitGeneric(copyType(paramType, getCurrOwner(c), false))
|
result = addImplicitGeneric(copyType(paramType, getCurrOwner(c), false))
|
||||||
|
|
||||||
of tyGenericParam:
|
of tyGenericParam:
|
||||||
markUsed(c.config, paramType.sym.info, paramType.sym, c.graph.usageSym)
|
markUsed(c, paramType.sym.info, paramType.sym, c.graph.usageSym)
|
||||||
onUse(paramType.sym.info, paramType.sym)
|
onUse(paramType.sym.info, paramType.sym)
|
||||||
if tfWildcard in paramType.flags:
|
if tfWildcard in paramType.flags:
|
||||||
paramType.flags.excl tfWildcard
|
paramType.flags.excl tfWildcard
|
||||||
|
|
@ -1751,7 +1751,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
else:
|
else:
|
||||||
assignType(prev, t)
|
assignType(prev, t)
|
||||||
result = prev
|
result = prev
|
||||||
markUsed(c.config, n.info, n.sym, c.graph.usageSym)
|
markUsed(c, n.info, n.sym, c.graph.usageSym)
|
||||||
onUse(n.info, n.sym)
|
onUse(n.info, n.sym)
|
||||||
else:
|
else:
|
||||||
if s.kind != skError:
|
if s.kind != skError:
|
||||||
|
|
|
||||||
|
|
@ -99,7 +99,7 @@ type
|
||||||
const
|
const
|
||||||
isNilConversion = isConvertible # maybe 'isIntConv' fits better?
|
isNilConversion = isConvertible # maybe 'isIntConv' fits better?
|
||||||
|
|
||||||
proc markUsed*(conf: ConfigRef; info: TLineInfo, s: PSym; usageSym: var PSym)
|
proc markUsed*(c: PContext; info: TLineInfo, s: PSym; usageSym: var PSym)
|
||||||
|
|
||||||
template hasFauxMatch*(c: TCandidate): bool = c.fauxMatch != tyNone
|
template hasFauxMatch*(c: TCandidate): bool = c.fauxMatch != tyNone
|
||||||
|
|
||||||
|
|
@ -1882,7 +1882,7 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType,
|
||||||
dest = generateTypeInstance(c, m.bindings, arg, dest)
|
dest = generateTypeInstance(c, m.bindings, arg, dest)
|
||||||
let fdest = typeRel(m, f, dest)
|
let fdest = typeRel(m, f, dest)
|
||||||
if fdest in {isEqual, isGeneric} and not (dest.kind == tyLent and f.kind == tyVar):
|
if fdest in {isEqual, isGeneric} and not (dest.kind == tyLent and f.kind == tyVar):
|
||||||
markUsed(c.config, arg.info, c.converters[i], c.graph.usageSym)
|
markUsed(c, arg.info, c.converters[i], c.graph.usageSym)
|
||||||
var s = newSymNode(c.converters[i])
|
var s = newSymNode(c.converters[i])
|
||||||
s.typ = c.converters[i].typ
|
s.typ = c.converters[i].typ
|
||||||
s.info = arg.info
|
s.info = arg.info
|
||||||
|
|
@ -2211,7 +2211,7 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
|
||||||
else: result = nil
|
else: result = nil
|
||||||
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, arg.info, arg.sons[best].sym, m.c.graph.usageSym)
|
||||||
onUse(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)
|
||||||
|
|
|
||||||
|
|
@ -528,7 +528,21 @@ proc userError(conf: ConfigRef; info: TLineInfo; s: PSym) =
|
||||||
return
|
return
|
||||||
localError(conf, info, "usage of '$1' is a user-defined error" % s.name.s)
|
localError(conf, info, "usage of '$1' is a user-defined error" % s.name.s)
|
||||||
|
|
||||||
proc markUsed(conf: ConfigRef; info: TLineInfo; s: PSym; usageSym: var PSym) =
|
proc markOwnerModuleAsUsed(c: PContext; s: PSym) =
|
||||||
|
var module = s
|
||||||
|
while module != nil and module.kind != skModule:
|
||||||
|
module = module.owner
|
||||||
|
if module != nil and module != c.module:
|
||||||
|
var i = 0
|
||||||
|
while i <= high(c.unusedImports):
|
||||||
|
if c.unusedImports[i][0] == module:
|
||||||
|
# mark it as used:
|
||||||
|
c.unusedImports.del(i)
|
||||||
|
else:
|
||||||
|
inc i
|
||||||
|
|
||||||
|
proc markUsed(c: PContext; info: TLineInfo; s: PSym; usageSym: var PSym) =
|
||||||
|
let conf = c.config
|
||||||
incl(s.flags, sfUsed)
|
incl(s.flags, sfUsed)
|
||||||
if s.kind == skEnumField and s.owner != nil:
|
if s.kind == skEnumField and s.owner != nil:
|
||||||
incl(s.owner.flags, sfUsed)
|
incl(s.owner.flags, sfUsed)
|
||||||
|
|
@ -541,6 +555,7 @@ proc markUsed(conf: ConfigRef; info: TLineInfo; s: PSym; usageSym: var PSym) =
|
||||||
suggestSym(conf, info, s, usageSym, false)
|
suggestSym(conf, info, s, usageSym, false)
|
||||||
if {optStyleHint, optStyleError} * conf.globalOptions != {}:
|
if {optStyleHint, optStyleError} * conf.globalOptions != {}:
|
||||||
styleCheckUse(conf, info, s)
|
styleCheckUse(conf, info, s)
|
||||||
|
markOwnerModuleAsUsed(c, s)
|
||||||
|
|
||||||
proc safeSemExpr*(c: PContext, n: PNode): PNode =
|
proc safeSemExpr*(c: PContext, n: PNode): PNode =
|
||||||
# use only for idetools support!
|
# use only for idetools support!
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue