fixes #11809
This commit is contained in:
parent
e3c0bf48c5
commit
04708742e7
5 changed files with 76 additions and 27 deletions
|
|
@ -31,7 +31,7 @@ proc importPureEnumField*(c: PContext; s: PSym) =
|
||||||
incl(c.ambiguousSymbols, checkB.id)
|
incl(c.ambiguousSymbols, checkB.id)
|
||||||
incl(c.ambiguousSymbols, s.id)
|
incl(c.ambiguousSymbols, s.id)
|
||||||
|
|
||||||
proc rawImportSymbol(c: PContext, s: PSym) =
|
proc rawImportSymbol(c: PContext, s, origin: PSym) =
|
||||||
# This does not handle stubs, because otherwise loading on demand would be
|
# This does not handle stubs, because otherwise loading on demand would be
|
||||||
# pointless in practice. So importing stubs is fine here!
|
# pointless in practice. So importing stubs is fine here!
|
||||||
# check if we have already a symbol of the same name:
|
# check if we have already a symbol of the same name:
|
||||||
|
|
@ -63,13 +63,14 @@ proc rawImportSymbol(c: PContext, s: PSym) =
|
||||||
check = nextIdentIter(it, c.importTable.symbols)
|
check = nextIdentIter(it, c.importTable.symbols)
|
||||||
if e != nil:
|
if e != nil:
|
||||||
if sfPure notin s.flags:
|
if sfPure notin s.flags:
|
||||||
rawImportSymbol(c, e)
|
rawImportSymbol(c, e, origin)
|
||||||
else:
|
else:
|
||||||
importPureEnumField(c, e)
|
importPureEnumField(c, e)
|
||||||
else:
|
else:
|
||||||
# rodgen assures that converters and patterns are no stubs
|
|
||||||
if s.kind == skConverter: addConverter(c, s)
|
if s.kind == skConverter: addConverter(c, s)
|
||||||
if hasPattern(s): addPattern(c, s)
|
if hasPattern(s): addPattern(c, s)
|
||||||
|
if s.owner != origin:
|
||||||
|
c.exportIndirections.incl(idPairToInt(origin.id, s.id))
|
||||||
|
|
||||||
proc importSymbol(c: PContext, n: PNode, fromMod: PSym) =
|
proc importSymbol(c: PContext, n: PNode, fromMod: PSym) =
|
||||||
let ident = lookups.considerQuotedIdent(c, n)
|
let ident = lookups.considerQuotedIdent(c, n)
|
||||||
|
|
@ -88,10 +89,10 @@ proc importSymbol(c: PContext, n: PNode, fromMod: PSym) =
|
||||||
while e != nil:
|
while e != nil:
|
||||||
if e.name.id != s.name.id: internalError(c.config, n.info, "importSymbol: 3")
|
if e.name.id != s.name.id: internalError(c.config, n.info, "importSymbol: 3")
|
||||||
if s.kind in ExportableSymKinds:
|
if s.kind in ExportableSymKinds:
|
||||||
rawImportSymbol(c, e)
|
rawImportSymbol(c, e, fromMod)
|
||||||
e = nextIdentIter(it, fromMod.tab)
|
e = nextIdentIter(it, fromMod.tab)
|
||||||
else:
|
else:
|
||||||
rawImportSymbol(c, s)
|
rawImportSymbol(c, s, fromMod)
|
||||||
suggestSym(c.config, n.info, s, c.graph.usageSym, false)
|
suggestSym(c.config, n.info, s, c.graph.usageSym, false)
|
||||||
|
|
||||||
proc importAllSymbolsExcept(c: PContext, fromMod: PSym, exceptSet: IntSet) =
|
proc importAllSymbolsExcept(c: PContext, fromMod: PSym, exceptSet: IntSet) =
|
||||||
|
|
@ -103,14 +104,14 @@ proc importAllSymbolsExcept(c: PContext, fromMod: PSym, exceptSet: IntSet) =
|
||||||
if s.kind notin ExportableSymKinds:
|
if s.kind notin ExportableSymKinds:
|
||||||
internalError(c.config, s.info, "importAllSymbols: " & $s.kind & " " & s.name.s)
|
internalError(c.config, s.info, "importAllSymbols: " & $s.kind & " " & s.name.s)
|
||||||
if exceptSet.isNil or s.name.id notin exceptSet:
|
if exceptSet.isNil or s.name.id notin exceptSet:
|
||||||
rawImportSymbol(c, s)
|
rawImportSymbol(c, s, fromMod)
|
||||||
s = nextIter(i, fromMod.tab)
|
s = nextIter(i, fromMod.tab)
|
||||||
|
|
||||||
proc importAllSymbols*(c: PContext, fromMod: PSym) =
|
proc importAllSymbols*(c: PContext, fromMod: PSym) =
|
||||||
var exceptSet: IntSet
|
var exceptSet: IntSet
|
||||||
importAllSymbolsExcept(c, fromMod, exceptSet)
|
importAllSymbolsExcept(c, fromMod, exceptSet)
|
||||||
|
|
||||||
proc importForwarded(c: PContext, n: PNode, exceptSet: IntSet) =
|
proc importForwarded(c: PContext, n: PNode, exceptSet: IntSet; fromMod: PSym) =
|
||||||
if n.isNil: return
|
if n.isNil: return
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkExportStmt:
|
of nkExportStmt:
|
||||||
|
|
@ -120,12 +121,12 @@ proc importForwarded(c: PContext, n: PNode, exceptSet: IntSet) =
|
||||||
if s.kind == skModule:
|
if s.kind == skModule:
|
||||||
importAllSymbolsExcept(c, s, exceptSet)
|
importAllSymbolsExcept(c, s, exceptSet)
|
||||||
elif exceptSet.isNil or s.name.id notin exceptSet:
|
elif exceptSet.isNil or s.name.id notin exceptSet:
|
||||||
rawImportSymbol(c, s)
|
rawImportSymbol(c, s, fromMod)
|
||||||
of nkExportExceptStmt:
|
of nkExportExceptStmt:
|
||||||
localError(c.config, n.info, "'export except' not implemented")
|
localError(c.config, n.info, "'export except' not implemented")
|
||||||
else:
|
else:
|
||||||
for i in 0..safeLen(n)-1:
|
for i in 0..safeLen(n)-1:
|
||||||
importForwarded(c, n.sons[i], exceptSet)
|
importForwarded(c, n.sons[i], exceptSet, fromMod)
|
||||||
|
|
||||||
proc importModuleAs(c: PContext; n: PNode, realModule: PSym): PSym =
|
proc importModuleAs(c: PContext; n: PNode, realModule: PSym): PSym =
|
||||||
result = realModule
|
result = realModule
|
||||||
|
|
@ -186,7 +187,7 @@ proc impMod(c: PContext; it: PNode; importStmtResult: PNode) =
|
||||||
# ``addDecl`` needs to be done before ``importAllSymbols``!
|
# ``addDecl`` needs to be done before ``importAllSymbols``!
|
||||||
addDecl(c, m, it.info) # add symbol to symbol table of module
|
addDecl(c, m, it.info) # add symbol to symbol table of module
|
||||||
importAllSymbolsExcept(c, m, emptySet)
|
importAllSymbolsExcept(c, m, emptySet)
|
||||||
#importForwarded(c, m.ast, emptySet)
|
#importForwarded(c, m.ast, emptySet, m)
|
||||||
|
|
||||||
proc evalImport*(c: PContext, n: PNode): PNode =
|
proc evalImport*(c: PContext, n: PNode): PNode =
|
||||||
result = newNodeI(nkImportStmt, n.info)
|
result = newNodeI(nkImportStmt, n.info)
|
||||||
|
|
@ -233,4 +234,4 @@ proc evalImportExcept*(c: PContext, n: PNode): PNode =
|
||||||
n.sons[0] = newSymNode(m)
|
n.sons[0] = newSymNode(m)
|
||||||
addDecl(c, m, n.info) # add symbol to symbol table of module
|
addDecl(c, m, n.info) # add symbol to symbol table of module
|
||||||
importAllSymbolsExcept(c, m, readExceptSet(c, n))
|
importAllSymbolsExcept(c, m, readExceptSet(c, n))
|
||||||
#importForwarded(c, m.ast, exceptSet)
|
#importForwarded(c, m.ast, exceptSet, m)
|
||||||
|
|
|
||||||
|
|
@ -138,6 +138,9 @@ type
|
||||||
# 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)]
|
unusedImports*: seq[(PSym, TLineInfo)]
|
||||||
|
exportIndirections*: IntSet
|
||||||
|
|
||||||
|
template idPairToInt*(a, b: int): int = a * 10_000_000 + b
|
||||||
|
|
||||||
template config*(c: PContext): ConfigRef = c.graph.config
|
template config*(c: PContext): ConfigRef = c.graph.config
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2130,30 +2130,42 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
|
||||||
result = n
|
result = n
|
||||||
case s.magic # magics that need special treatment
|
case s.magic # magics that need special treatment
|
||||||
of mAddr:
|
of mAddr:
|
||||||
|
markUsed(c, n.info, s, c.graph.usageSym)
|
||||||
checkSonsLen(n, 2, c.config)
|
checkSonsLen(n, 2, c.config)
|
||||||
result[0] = newSymNode(s, n[0].info)
|
result[0] = newSymNode(s, n[0].info)
|
||||||
result[1] = semAddrArg(c, n.sons[1], s.name.s == "unsafeAddr")
|
result[1] = semAddrArg(c, n.sons[1], s.name.s == "unsafeAddr")
|
||||||
result.typ = makePtrType(c, result[1].typ)
|
result.typ = makePtrType(c, result[1].typ)
|
||||||
of mTypeOf:
|
of mTypeOf:
|
||||||
|
markUsed(c, n.info, s, c.graph.usageSym)
|
||||||
result = semTypeOf(c, n)
|
result = semTypeOf(c, n)
|
||||||
#of mArrGet: result = semArrGet(c, n, flags)
|
of mDefined:
|
||||||
#of mArrPut: result = semArrPut(c, n, flags)
|
markUsed(c, n.info, s, c.graph.usageSym)
|
||||||
#of mAsgn: result = semAsgnOpr(c, n)
|
result = semDefined(c, setMs(n, s), false)
|
||||||
of mDefined: result = semDefined(c, setMs(n, s), false)
|
of mDefinedInScope:
|
||||||
of mDefinedInScope: result = semDefined(c, setMs(n, s), true)
|
markUsed(c, n.info, s, c.graph.usageSym)
|
||||||
of mCompiles: result = semCompiles(c, setMs(n, s), flags)
|
result = semDefined(c, setMs(n, s), true)
|
||||||
#of mLow: result = semLowHigh(c, setMs(n, s), mLow)
|
of mCompiles:
|
||||||
#of mHigh: result = semLowHigh(c, setMs(n, s), mHigh)
|
markUsed(c, n.info, s, c.graph.usageSym)
|
||||||
of mIs: result = semIs(c, setMs(n, s), flags)
|
result = semCompiles(c, setMs(n, s), flags)
|
||||||
#of mOf: result = semOf(c, setMs(n, s))
|
of mIs:
|
||||||
of mShallowCopy: result = semShallowCopy(c, n, flags)
|
markUsed(c, n.info, s, c.graph.usageSym)
|
||||||
of mExpandToAst: result = semExpandToAst(c, n, s, flags)
|
result = semIs(c, setMs(n, s), flags)
|
||||||
of mQuoteAst: result = semQuoteAst(c, n)
|
of mShallowCopy:
|
||||||
|
markUsed(c, n.info, s, c.graph.usageSym)
|
||||||
|
result = semShallowCopy(c, n, flags)
|
||||||
|
of mExpandToAst:
|
||||||
|
markUsed(c, n.info, s, c.graph.usageSym)
|
||||||
|
result = semExpandToAst(c, n, s, flags)
|
||||||
|
of mQuoteAst:
|
||||||
|
markUsed(c, n.info, s, c.graph.usageSym)
|
||||||
|
result = semQuoteAst(c, n)
|
||||||
of mAstToStr:
|
of mAstToStr:
|
||||||
|
markUsed(c, n.info, s, c.graph.usageSym)
|
||||||
checkSonsLen(n, 2, c.config)
|
checkSonsLen(n, 2, c.config)
|
||||||
result = newStrNodeT(renderTree(n[1], {renderNoComments}), n, c.graph)
|
result = newStrNodeT(renderTree(n[1], {renderNoComments}), n, c.graph)
|
||||||
result.typ = getSysType(c.graph, n.info, tyString)
|
result.typ = getSysType(c.graph, n.info, tyString)
|
||||||
of mParallel:
|
of mParallel:
|
||||||
|
markUsed(c, n.info, s, c.graph.usageSym)
|
||||||
if parallel notin c.features:
|
if parallel notin c.features:
|
||||||
localError(c.config, n.info, "use the {.experimental.} pragma to enable 'parallel'")
|
localError(c.config, n.info, "use the {.experimental.} pragma to enable 'parallel'")
|
||||||
result = setMs(n, s)
|
result = setMs(n, s)
|
||||||
|
|
@ -2163,6 +2175,7 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
|
||||||
result.sons[1] = semStmt(c, x, {})
|
result.sons[1] = semStmt(c, x, {})
|
||||||
dec c.inParallelStmt
|
dec c.inParallelStmt
|
||||||
of mSpawn:
|
of mSpawn:
|
||||||
|
markUsed(c, n.info, s, c.graph.usageSym)
|
||||||
when defined(leanCompiler):
|
when defined(leanCompiler):
|
||||||
localError(c.config, n.info, "compiler was built without 'spawn' support")
|
localError(c.config, n.info, "compiler was built without 'spawn' support")
|
||||||
result = n
|
result = n
|
||||||
|
|
@ -2180,10 +2193,12 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
|
||||||
else:
|
else:
|
||||||
result.add c.graph.emptyNode
|
result.add c.graph.emptyNode
|
||||||
of mProcCall:
|
of mProcCall:
|
||||||
|
markUsed(c, n.info, s, c.graph.usageSym)
|
||||||
result = setMs(n, s)
|
result = setMs(n, s)
|
||||||
result.sons[1] = semExpr(c, n.sons[1])
|
result.sons[1] = semExpr(c, n.sons[1])
|
||||||
result.typ = n[1].typ
|
result.typ = n[1].typ
|
||||||
of mPlugin:
|
of mPlugin:
|
||||||
|
markUsed(c, n.info, s, c.graph.usageSym)
|
||||||
# semDirectOp with conditional 'afterCallActions':
|
# semDirectOp with conditional 'afterCallActions':
|
||||||
let nOrig = n.copyTree
|
let nOrig = n.copyTree
|
||||||
#semLazyOpAux(c, n)
|
#semLazyOpAux(c, n)
|
||||||
|
|
@ -2200,6 +2215,7 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
|
||||||
if callee.magic != mNone:
|
if callee.magic != mNone:
|
||||||
result = magicsAfterOverloadResolution(c, result, flags)
|
result = magicsAfterOverloadResolution(c, result, flags)
|
||||||
of mRunnableExamples:
|
of mRunnableExamples:
|
||||||
|
markUsed(c, n.info, s, c.graph.usageSym)
|
||||||
if c.config.cmd == cmdDoc and n.len >= 2 and n.lastSon.kind == nkStmtList:
|
if c.config.cmd == cmdDoc and n.len >= 2 and n.lastSon.kind == nkStmtList:
|
||||||
when false:
|
when false:
|
||||||
# some of this dead code was moved to `prepareExamples`
|
# some of this dead code was moved to `prepareExamples`
|
||||||
|
|
@ -2216,8 +2232,9 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
|
||||||
result = setMs(n, s)
|
result = setMs(n, s)
|
||||||
else:
|
else:
|
||||||
result = c.graph.emptyNode
|
result = c.graph.emptyNode
|
||||||
of mSizeOf: result =
|
of mSizeOf:
|
||||||
semSizeof(c, setMs(n, s))
|
markUsed(c, n.info, s, c.graph.usageSym)
|
||||||
|
result = semSizeof(c, setMs(n, s))
|
||||||
else:
|
else:
|
||||||
result = semDirectOp(c, n, flags)
|
result = semDirectOp(c, n, flags)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -535,7 +535,8 @@ proc markOwnerModuleAsUsed(c: PContext; s: PSym) =
|
||||||
if module != nil and module != c.module:
|
if module != nil and module != c.module:
|
||||||
var i = 0
|
var i = 0
|
||||||
while i <= high(c.unusedImports):
|
while i <= high(c.unusedImports):
|
||||||
if c.unusedImports[i][0] == module:
|
let candidate = c.unusedImports[i][0]
|
||||||
|
if candidate == module or c.exportIndirections.contains(idPairToInt(candidate.id, s.id)):
|
||||||
# mark it as used:
|
# mark it as used:
|
||||||
c.unusedImports.del(i)
|
c.unusedImports.del(i)
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
27
tests/tools/tunused_imports.nim
Normal file
27
tests/tools/tunused_imports.nim
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
discard """
|
||||||
|
cmd: '''nim c --hint[Processing]:off $file'''
|
||||||
|
nimout: '''
|
||||||
|
tunused_imports.nim(11, 10) Warning: BEGIN [User]
|
||||||
|
tunused_imports.nim(27, 10) Warning: END [User]
|
||||||
|
tunused_imports.nim(25, 8) Warning: imported and not used: 'strutils' [UnusedImport]
|
||||||
|
'''
|
||||||
|
action: "compile"
|
||||||
|
"""
|
||||||
|
|
||||||
|
{.warning: "BEGIN".}
|
||||||
|
|
||||||
|
import net
|
||||||
|
|
||||||
|
echo AF_UNIX
|
||||||
|
|
||||||
|
import macros
|
||||||
|
# bug #11809
|
||||||
|
macro bar(): untyped =
|
||||||
|
template baz() = discard
|
||||||
|
result = getAst(baz())
|
||||||
|
|
||||||
|
bar()
|
||||||
|
|
||||||
|
import strutils
|
||||||
|
|
||||||
|
{.warning: "END".}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue