diff options
-rw-r--r-- | compiler/importer.nim | 23 | ||||
-rw-r--r-- | compiler/semdata.nim | 3 | ||||
-rw-r--r-- | compiler/semexprs.nim | 47 | ||||
-rw-r--r-- | compiler/suggest.nim | 3 | ||||
-rw-r--r-- | tests/tools/tunused_imports.nim | 27 |
5 files changed, 76 insertions, 27 deletions
diff --git a/compiler/importer.nim b/compiler/importer.nim index e42a4d816..d048d7fe1 100644 --- a/compiler/importer.nim +++ b/compiler/importer.nim @@ -31,7 +31,7 @@ proc importPureEnumField*(c: PContext; s: PSym) = incl(c.ambiguousSymbols, checkB.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 # pointless in practice. So importing stubs is fine here! # 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) if e != nil: if sfPure notin s.flags: - rawImportSymbol(c, e) + rawImportSymbol(c, e, origin) else: importPureEnumField(c, e) else: - # rodgen assures that converters and patterns are no stubs if s.kind == skConverter: addConverter(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) = let ident = lookups.considerQuotedIdent(c, n) @@ -88,10 +89,10 @@ proc importSymbol(c: PContext, n: PNode, fromMod: PSym) = while e != nil: if e.name.id != s.name.id: internalError(c.config, n.info, "importSymbol: 3") if s.kind in ExportableSymKinds: - rawImportSymbol(c, e) + rawImportSymbol(c, e, fromMod) e = nextIdentIter(it, fromMod.tab) else: - rawImportSymbol(c, s) + rawImportSymbol(c, s, fromMod) suggestSym(c.config, n.info, s, c.graph.usageSym, false) 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: internalError(c.config, s.info, "importAllSymbols: " & $s.kind & " " & s.name.s) if exceptSet.isNil or s.name.id notin exceptSet: - rawImportSymbol(c, s) + rawImportSymbol(c, s, fromMod) s = nextIter(i, fromMod.tab) proc importAllSymbols*(c: PContext, fromMod: PSym) = var exceptSet: IntSet 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 case n.kind of nkExportStmt: @@ -120,12 +121,12 @@ proc importForwarded(c: PContext, n: PNode, exceptSet: IntSet) = if s.kind == skModule: importAllSymbolsExcept(c, s, exceptSet) elif exceptSet.isNil or s.name.id notin exceptSet: - rawImportSymbol(c, s) + rawImportSymbol(c, s, fromMod) of nkExportExceptStmt: localError(c.config, n.info, "'export except' not implemented") else: 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 = result = realModule @@ -186,7 +187,7 @@ proc impMod(c: PContext; it: PNode; importStmtResult: PNode) = # ``addDecl`` needs to be done before ``importAllSymbols``! addDecl(c, m, it.info) # add symbol to symbol table of module importAllSymbolsExcept(c, m, emptySet) - #importForwarded(c, m.ast, emptySet) + #importForwarded(c, m.ast, emptySet, m) proc evalImport*(c: PContext, n: PNode): PNode = result = newNodeI(nkImportStmt, n.info) @@ -233,4 +234,4 @@ proc evalImportExcept*(c: PContext, n: PNode): PNode = n.sons[0] = newSymNode(m) addDecl(c, m, n.info) # add symbol to symbol table of module importAllSymbolsExcept(c, m, readExceptSet(c, n)) - #importForwarded(c, m.ast, exceptSet) + #importForwarded(c, m.ast, exceptSet, m) diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 5638fd29e..464c55b7e 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -138,6 +138,9 @@ type # tests/destructor/topttree.nim for an example that # would otherwise fail. 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 diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 439a0070e..dc3076ceb 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -2130,30 +2130,42 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = result = n case s.magic # magics that need special treatment of mAddr: + markUsed(c, n.info, s, c.graph.usageSym) checkSonsLen(n, 2, c.config) result[0] = newSymNode(s, n[0].info) result[1] = semAddrArg(c, n.sons[1], s.name.s == "unsafeAddr") result.typ = makePtrType(c, result[1].typ) of mTypeOf: + markUsed(c, n.info, s, c.graph.usageSym) result = semTypeOf(c, n) - #of mArrGet: result = semArrGet(c, n, flags) - #of mArrPut: result = semArrPut(c, n, flags) - #of mAsgn: result = semAsgnOpr(c, n) - of mDefined: result = semDefined(c, setMs(n, s), false) - of mDefinedInScope: result = semDefined(c, setMs(n, s), true) - of mCompiles: result = semCompiles(c, setMs(n, s), flags) - #of mLow: result = semLowHigh(c, setMs(n, s), mLow) - #of mHigh: result = semLowHigh(c, setMs(n, s), mHigh) - of mIs: result = semIs(c, setMs(n, s), flags) - #of mOf: result = semOf(c, setMs(n, s)) - of mShallowCopy: result = semShallowCopy(c, n, flags) - of mExpandToAst: result = semExpandToAst(c, n, s, flags) - of mQuoteAst: result = semQuoteAst(c, n) + of mDefined: + markUsed(c, n.info, s, c.graph.usageSym) + result = semDefined(c, setMs(n, s), false) + of mDefinedInScope: + markUsed(c, n.info, s, c.graph.usageSym) + result = semDefined(c, setMs(n, s), true) + of mCompiles: + markUsed(c, n.info, s, c.graph.usageSym) + result = semCompiles(c, setMs(n, s), flags) + of mIs: + markUsed(c, n.info, s, c.graph.usageSym) + result = semIs(c, setMs(n, s), flags) + 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: + markUsed(c, n.info, s, c.graph.usageSym) checkSonsLen(n, 2, c.config) result = newStrNodeT(renderTree(n[1], {renderNoComments}), n, c.graph) result.typ = getSysType(c.graph, n.info, tyString) of mParallel: + markUsed(c, n.info, s, c.graph.usageSym) if parallel notin c.features: localError(c.config, n.info, "use the {.experimental.} pragma to enable 'parallel'") 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, {}) dec c.inParallelStmt of mSpawn: + markUsed(c, n.info, s, c.graph.usageSym) when defined(leanCompiler): localError(c.config, n.info, "compiler was built without 'spawn' support") result = n @@ -2180,10 +2193,12 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = else: result.add c.graph.emptyNode of mProcCall: + markUsed(c, n.info, s, c.graph.usageSym) result = setMs(n, s) result.sons[1] = semExpr(c, n.sons[1]) result.typ = n[1].typ of mPlugin: + markUsed(c, n.info, s, c.graph.usageSym) # semDirectOp with conditional 'afterCallActions': let nOrig = n.copyTree #semLazyOpAux(c, n) @@ -2200,6 +2215,7 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = if callee.magic != mNone: result = magicsAfterOverloadResolution(c, result, flags) of mRunnableExamples: + markUsed(c, n.info, s, c.graph.usageSym) if c.config.cmd == cmdDoc and n.len >= 2 and n.lastSon.kind == nkStmtList: when false: # 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) else: result = c.graph.emptyNode - of mSizeOf: result = - semSizeof(c, setMs(n, s)) + of mSizeOf: + markUsed(c, n.info, s, c.graph.usageSym) + result = semSizeof(c, setMs(n, s)) else: result = semDirectOp(c, n, flags) diff --git a/compiler/suggest.nim b/compiler/suggest.nim index 59e3a7242..620f4830a 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -535,7 +535,8 @@ proc markOwnerModuleAsUsed(c: PContext; s: PSym) = if module != nil and module != c.module: var i = 0 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: c.unusedImports.del(i) else: diff --git a/tests/tools/tunused_imports.nim b/tests/tools/tunused_imports.nim new file mode 100644 index 000000000..c9cfcfe90 --- /dev/null +++ b/tests/tools/tunused_imports.nim @@ -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".} |