diff options
author | Araq <rumpf_a@web.de> | 2019-07-10 00:27:23 +0200 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2019-07-10 00:29:58 +0200 |
commit | bd689849f28ba98b9b2581605234a2b52fb2e392 (patch) | |
tree | 868b293cda5151623b6083044bd7a7a0c187713e /compiler | |
parent | c6c9e30379dbf1016f336495b073b233fe1a2563 (diff) | |
download | Nim-bd689849f28ba98b9b2581605234a2b52fb2e392.tar.gz |
nim styleChecker: implemented all the missing features (bugfix)
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/lexer.nim | 8 | ||||
-rw-r--r-- | compiler/lineinfos.nim | 2 | ||||
-rw-r--r-- | compiler/linter.nim | 96 | ||||
-rw-r--r-- | compiler/msgs.nim | 7 | ||||
-rw-r--r-- | compiler/pragmas.nim | 13 | ||||
-rw-r--r-- | compiler/suggest.nim | 4 |
6 files changed, 80 insertions, 50 deletions
diff --git a/compiler/lexer.nim b/compiler/lexer.nim index 18479c5eb..19f1b828d 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -878,6 +878,7 @@ proc getSymbol(L: var TLexer, tok: var TToken) = var h: Hash = 0 var pos = L.bufpos tokenBegin(tok, pos) + var suspicious = false while true: var c = L.buf[pos] case c @@ -888,21 +889,26 @@ proc getSymbol(L: var TLexer, tok: var TToken) = c = chr(ord(c) + (ord('a') - ord('A'))) # toLower() h = h !& ord(c) inc(pos) + suspicious = true of '_': if L.buf[pos+1] notin SymChars: lexMessage(L, errGenerated, "invalid token: trailing underscore") break inc(pos) + suspicious = true else: break tokenEnd(tok, pos-1) h = !$h tok.ident = L.cache.getIdent(addr(L.buf[L.bufpos]), pos - L.bufpos, h) - L.bufpos = pos if (tok.ident.id < ord(tokKeywordLow) - ord(tkSymbol)) or (tok.ident.id > ord(tokKeywordHigh) - ord(tkSymbol)): tok.tokType = tkSymbol else: tok.tokType = TTokType(tok.ident.id + ord(tkSymbol)) + if suspicious and {optStyleHint, optStyleError} * L.config.globalOptions != {}: + lintReport(L.config, getLineInfo(L), tok.ident.s.normalize, tok.ident.s) + L.bufpos = pos + proc endOperator(L: var TLexer, tok: var TToken, pos: int, hash: Hash) {.inline.} = diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index 694ae8e94..b6707f11b 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -108,7 +108,7 @@ const hintPath: "added path: '$1'", hintConditionAlwaysTrue: "condition is always true: '$1'", hintConditionAlwaysFalse: "condition is always false: '$1'", - hintName: "name should be: '$1'", + hintName: "$1", hintPattern: "$1", hintExecuting: "$1", hintLinking: "", diff --git a/compiler/linter.nim b/compiler/linter.nim index a881f2711..d1d3140c0 100644 --- a/compiler/linter.nim +++ b/compiler/linter.nim @@ -25,17 +25,12 @@ proc identLen*(line: string, start: int): int = type StyleCheck* {.pure.} = enum None, Warn, Auto -var - gOverWrite* = true - gStyleCheck*: StyleCheck - gCheckExtern*, gOnlyMainfile*: bool - proc overwriteFiles*(conf: ConfigRef) = let doStrip = options.getConfigVar(conf, "pretty.strip").normalize == "on" for i in 0 .. high(conf.m.fileInfos): if conf.m.fileInfos[i].dirty and - (not gOnlyMainfile or FileIndex(i) == conf.projectMainIdx): - let newFile = if gOverWrite: conf.m.fileInfos[i].fullpath + (FileIndex(i) == conf.projectMainIdx): + let newFile = if false: conf.m.fileInfos[i].fullpath else: conf.m.fileInfos[i].fullpath.changeFileExt(".pretty.nim") try: var f = open(newFile.string, fmWrite) @@ -69,7 +64,7 @@ proc beautifyName(s: string, k: TSymKind): string = "pointer", "float", "csize", "cdouble", "cchar", "cschar", "cshort", "cu", "nil", "typedesc", "auto", "any", "range", "openarray", "varargs", "set", "cfloat", "ref", "ptr", - "untyped", "typed", "static", "sink", "lent", "type"]: + "untyped", "typed", "static", "sink", "lent", "type", "owned"]: result.add s[i] else: result.add toUpperAscii(s[i]) @@ -98,46 +93,23 @@ proc beautifyName(s: string, k: TSymKind): string = result.add s[i] inc i -proc differ*(line: string, a, b: int, x: string): bool = +proc differ*(line: string, a, b: int, x: string): string = let y = line[a..b] - result = cmpIgnoreStyle(y, x) == 0 and y != x - -proc replaceInFile(conf: ConfigRef; info: TLineInfo; newName: string) = - let line = conf.m.fileInfos[info.fileIndex.int].lines[info.line.int-1] - var first = min(info.col.int, line.len) - if first < 0: return - #inc first, skipIgnoreCase(line, "proc ", first) - while first > 0 and line[first-1] in Letters: dec first - if first < 0: return - if line[first] == '`': inc first - - let last = first+identLen(line, first)-1 - if differ(line, first, last, newName): - # last-first+1 != newName.len or - var x = line.substr(0, first-1) & newName & line.substr(last+1) - system.shallowCopy(conf.m.fileInfos[info.fileIndex.int].lines[info.line.int-1], x) - conf.m.fileInfos[info.fileIndex.int].dirty = true - -proc lintReport(conf: ConfigRef; info: TLineInfo, beau: string) = - if optStyleError in conf.globalOptions: - localError(conf, info, "name should be: '$1'" % beau) + if cmpIgnoreStyle(y, x) == 0 and y != x: + result = y else: - message(conf, info, hintName, beau) + result = "" proc checkStyle(conf: ConfigRef; cache: IdentCache; info: TLineInfo, s: string, k: TSymKind; sym: PSym) = let beau = beautifyName(s, k) if s != beau: - if gStyleCheck == StyleCheck.Auto: - sym.name = getIdent(cache, beau) - replaceInFile(conf, info, beau) - else: - lintReport(conf, info, beau) + lintReport(conf, info, beau, s) proc styleCheckDefImpl(conf: ConfigRef; cache: IdentCache; info: TLineInfo; s: PSym; k: TSymKind) = # operators stay as they are: if k in {skResult, skTemp} or s.name.s[0] notin Letters: return if k in {skType, skGenericParam} and sfAnon in s.flags: return - if {sfImportc, sfExportc} * s.flags == {} or gCheckExtern: + if {sfImportc, sfExportc} * s.flags == {}: checkStyle(conf, cache, info, s.name.s, k, s) proc nep1CheckDefImpl(conf: ConfigRef; info: TLineInfo; s: PSym; k: TSymKind) = @@ -148,7 +120,7 @@ proc nep1CheckDefImpl(conf: ConfigRef; info: TLineInfo; s: PSym; k: TSymKind) = if {sfImportc, sfExportc} * s.flags != {}: return let beau = beautifyName(s.name.s, k) if s.name.s != beau: - lintReport(conf, info, beau) + lintReport(conf, info, beau, s.name.s) template styleCheckDef*(conf: ConfigRef; info: TLineInfo; s: PSym; k: TSymKind) = if {optStyleHint, optStyleError} * conf.globalOptions != {}: @@ -161,19 +133,57 @@ template styleCheckDef*(conf: ConfigRef; info: TLineInfo; s: PSym) = template styleCheckDef*(conf: ConfigRef; s: PSym) = styleCheckDef(conf, s.info, s, s.kind) -proc styleCheckUseImpl(conf: ConfigRef; info: TLineInfo; s: PSym) = +proc differs(conf: ConfigRef; info: TLineInfo; newName: string): string = + let line = sourceLine(conf, info) + var first = min(info.col.int, line.len) + if first < 0: return + #inc first, skipIgnoreCase(line, "proc ", first) + while first > 0 and line[first-1] in Letters: dec first + if first < 0: return + if line[first] == '`': inc first + + let last = first+identLen(line, first)-1 + result = differ(line, first, last, newName) + +proc styleCheckUse*(conf: ConfigRef; info: TLineInfo; s: PSym) = if info.fileIndex.int < 0: return # we simply convert it to what it looks like in the definition # for consistency # operators stay as they are: - if s.kind in {skResult, skTemp} or s.name.s[0] notin Letters: + if s.kind == skTemp or s.name.s[0] notin Letters or sfAnon in s.flags: return - if s.kind in {skType, skGenericParam} and sfAnon in s.flags: return + let newName = s.name.s + let oldName = differs(conf, info, newName) + if oldName.len > 0: + lintReport(conf, info, newName, oldName) + +proc checkPragmaUse*(conf: ConfigRef; info: TLineInfo; pragmaName: string) = + const inMixedCase = [ + "noSideEffect", "importCompilerProc", "incompleteStruct", "requiresInit", + "sideEffect", "compilerProc", "lineDir", "stackTrace", "lineTrace", + "rangeChecks", "boundChecks", + "overflowChecks", "nilChecks", + "floatChecks", "nanChecks", "infChecks", "moveChecks", + "nonReloadable", "executeOnReload", + "deadCodeElim", + "compileTime", "noInit", "fieldChecks", + "linearScanEnd", + "computedGoto", "injectStmt", + "asmNoStackframe", "implicitStatic", "codegenDecl", "liftLocals" + ] + let name = pragmaName.normalize + for x in inMixedCase: + if x.normalize == name: + if pragmaName != x: + lintReport(conf, info, x, pragmaName) + return + + let wanted = pragmaName.toLowerAscii.replace("_", "") + if pragmaName != wanted: + lintReport(conf, info, wanted, pragmaName) - replaceInFile(conf, info, newName) - #if newName == "File": writeStackTrace() template styleCheckUse*(info: TLineInfo; s: PSym) = when defined(nimfix): diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 892f1af36..11c0b486b 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -588,3 +588,10 @@ proc listHints*(conf: ConfigRef) = if hint in conf.notes: "x" else: " ", lineinfos.HintsToStr[ord(hint) - ord(hintMin)] ]) + +proc lintReport*(conf: ConfigRef; info: TLineInfo, beau, got: string) = + let m = "'$2' should be: '$1'" % [beau, got] + if optStyleError in conf.globalOptions: + localError(conf, info, m) + else: + message(conf, info, hintName, m) diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 94e6a4332..b50b9ece2 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -12,7 +12,7 @@ import os, platform, condsyms, ast, astalgo, idents, semdata, msgs, renderer, wordrecg, ropes, options, strutils, extccomp, math, magicsys, trees, - types, lookups, lineinfos, pathutils + types, lookups, lineinfos, pathutils, linter const FirstCallConv* = wNimcall @@ -610,9 +610,9 @@ proc pragmaLine(c: PContext, n: PNode) = proc processPragma(c: PContext, n: PNode, i: int) = let it = n[i] - if it.kind notin nkPragmaCallKinds and it.len == 2: invalidPragma(c, n) - elif it[0].kind != nkIdent: invalidPragma(c, n) - elif it[1].kind != nkIdent: invalidPragma(c, n) + if it.kind notin nkPragmaCallKinds and it.safeLen == 2: invalidPragma(c, n) + elif it.safeLen != 2 or it[0].kind != nkIdent or it[1].kind != nkIdent: + invalidPragma(c, n) var userPragma = newSym(skTemplate, it[1].ident, nil, it.info, c.config.options) userPragma.ast = newNode(nkPragma, n.info, n.sons[i+1..^1]) @@ -762,6 +762,9 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, let ident = considerQuotedIdent(c, key) var userPragma = strTableGet(c.userPragmas, ident) if userPragma != nil: + if {optStyleHint, optStyleError} * c.config.globalOptions != {}: + styleCheckUse(c.config, key.info, userPragma) + # number of pragmas increase/decrease with user pragma expansion inc c.instCounter if c.instCounter > 100: @@ -774,6 +777,8 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, else: let k = whichKeyword(ident) if k in validPragmas: + if {optStyleHint, optStyleError} * c.config.globalOptions != {}: + checkPragmaUse(c.config, key.info, ident.s) case k of wExportc: makeExternExport(c, sym, getOptionalStr(c, it, "$1"), it.info) diff --git a/compiler/suggest.nim b/compiler/suggest.nim index e98451510..705d723d1 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -32,7 +32,7 @@ # included from sigmatch.nim -import algorithm, prefixmatches, lineinfos, pathutils, parseutils +import algorithm, prefixmatches, lineinfos, pathutils, parseutils, linter from wordrecg import wDeprecated, wError, wAddr, wYield, specialWords when defined(nimsuggest): @@ -539,6 +539,8 @@ proc markUsed(conf: ConfigRef; info: TLineInfo; s: PSym; usageSym: var PSym) = if sfError in s.flags: userError(conf, info, s) when defined(nimsuggest): suggestSym(conf, info, s, usageSym, false) + if {optStyleHint, optStyleError} * conf.globalOptions != {}: + styleCheckUse(conf, info, s) proc safeSemExpr*(c: PContext, n: PNode): PNode = # use only for idetools support! |