[feature] detect unused imports

This commit is contained in:
Araq 2019-07-17 22:36:23 +02:00
commit 4137a4dbf3
12 changed files with 62 additions and 33 deletions

View file

@ -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 =

View file

@ -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",

View file

@ -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

View file

@ -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;

View file

@ -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)

View file

@ -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

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 =
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 =

View file

@ -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]':

View file

@ -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

View file

@ -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:

View file

@ -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)

View file

@ -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!