summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2019-07-10 00:27:23 +0200
committerAraq <rumpf_a@web.de>2019-07-10 00:29:58 +0200
commitbd689849f28ba98b9b2581605234a2b52fb2e392 (patch)
tree868b293cda5151623b6083044bd7a7a0c187713e /compiler
parentc6c9e30379dbf1016f336495b073b233fe1a2563 (diff)
downloadNim-bd689849f28ba98b9b2581605234a2b52fb2e392.tar.gz
nim styleChecker: implemented all the missing features (bugfix)
Diffstat (limited to 'compiler')
-rw-r--r--compiler/lexer.nim8
-rw-r--r--compiler/lineinfos.nim2
-rw-r--r--compiler/linter.nim96
-rw-r--r--compiler/msgs.nim7
-rw-r--r--compiler/pragmas.nim13
-rw-r--r--compiler/suggest.nim4
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!