diff --git a/src/dsymbol.c b/src/dsymbol.c index f5adba3cc691..5961a2bf9d06 100644 --- a/src/dsymbol.c +++ b/src/dsymbol.c @@ -415,7 +415,7 @@ Dsymbol *Dsymbol::search(Loc loc, Identifier *ident, int flags) * Search for symbol with correct spelling. */ -void *symbol_search_fp(void *arg, const char *seed) +void *symbol_search_fp(void *arg, const char *seed, int* cost) { /* If not in the lexer's string table, it certainly isn't in the symbol table. * Doing this first is a lot faster. @@ -429,9 +429,10 @@ void *symbol_search_fp(void *arg, const char *seed) Identifier *id = (Identifier *)sv->ptrvalue; assert(id); + *cost = 0; Dsymbol *s = (Dsymbol *)arg; Module::clearCache(); - return (void *)s->search(Loc(), id, IgnoreErrors | IgnoreAmbiguous); + return (void *)s->search(Loc(), id, IgnoreErrors); } Dsymbol *Dsymbol::search_correct(Identifier *ident) @@ -905,6 +906,7 @@ Dsymbol *ScopeDsymbol::search(Loc loc, Identifier *ident, int flags) { Dsymbol *s = NULL; OverloadSet *a = NULL; + int sflags = flags & (IgnoreErrors | IgnoreAmbiguous); // remember these in recursive searches // Look in imported modules for (size_t i = 0; i < imports->dim; i++) @@ -918,7 +920,7 @@ Dsymbol *ScopeDsymbol::search(Loc loc, Identifier *ident, int flags) //printf("\tscanning import '%s', prots = %d, isModule = %p, isImport = %p\n", ss->toChars(), prots[i], ss->isModule(), ss->isImport()); /* Don't find private members if ss is a module */ - Dsymbol *s2 = ss->search(loc, ident, ss->isModule() ? IgnorePrivateMembers : IgnoreNone); + Dsymbol *s2 = ss->search(loc, ident, sflags | (ss->isModule() ? IgnorePrivateMembers : IgnoreNone)); if (!s) { s = s2; diff --git a/src/root/speller.c b/src/root/speller.c index 6cc6cccc0b35..eba4e9bab8a5 100644 --- a/src/root/speller.c +++ b/src/root/speller.c @@ -11,6 +11,7 @@ #include #include #include +#include #if __sun || _MSC_VER #include @@ -21,21 +22,33 @@ const char idchars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"; /************************************************** - * Looks for correct spelling. - * Currently only looks a 'distance' of one from the seed[]. - * This does an exhaustive search, so can potentially be very slow. + * combine a new result from the spell checker to + * find the one with the closest symbol with + * respect to the cost defined by the search function + * Input/Output: + * p best found spelling (NULL if none found yet) + * cost cost of p (INT_MAX if none found yet) * Input: - * seed wrongly spelled word - * fp search function - * fparg argument to search function - * charset character set + * np new found spelling (NULL if none found) + * ncost cost of np if non-NULL * Returns: - * NULL no correct spellings found - * void* value returned by fp() for first possible correct spelling + * true if the cost is less or equal 0 + * false otherwise */ +bool combineSpellerResult(void*& p, int& cost, void* np, int ncost) +{ + if (np && ncost < cost) + { + p = np; + cost = ncost; + if (cost <= 0) + return true; + } + return false; +} void *spellerY(const char *seed, size_t seedlen, fp_speller_t fp, void *fparg, - const char *charset, size_t index) + const char *charset, size_t index, int* cost) { if (!seedlen) return NULL; @@ -53,14 +66,17 @@ void *spellerY(const char *seed, size_t seedlen, fp_speller_t fp, void *fparg, } memcpy(buf, seed, index); + *cost = INT_MAX; + void* p = NULL; + int ncost; /* Delete at seed[index] */ if (index < seedlen) { memcpy(buf + index, seed + index + 1, seedlen - index); assert(buf[seedlen - 1] == 0); - void *p = (*fp)(fparg, buf); - if (p) + void* np = (*fp)(fparg, buf, &ncost); + if (combineSpellerResult(p, *cost, np, ncost)) return p; } @@ -75,8 +91,8 @@ void *spellerY(const char *seed, size_t seedlen, fp_speller_t fp, void *fparg, buf[index] = *s; //printf("sub buf = '%s'\n", buf); - void *p = (*fp)(fparg, buf); - if (p) + void* np = (*fp)(fparg, buf, &ncost); + if (combineSpellerResult(p, *cost, np, ncost)) return p; } assert(buf[seedlen] == 0); @@ -90,14 +106,14 @@ void *spellerY(const char *seed, size_t seedlen, fp_speller_t fp, void *fparg, buf[index] = *s; //printf("ins buf = '%s'\n", buf); - void *p = (*fp)(fparg, buf); - if (p) + void* np = (*fp)(fparg, buf, &ncost); + if (combineSpellerResult(p, *cost, np, ncost)) return p; } assert(buf[seedlen + 1] == 0); } - return NULL; // didn't find any corrections + return p; // return "best" result } void *spellerX(const char *seed, size_t seedlen, fp_speller_t fp, void *fparg, @@ -116,18 +132,19 @@ void *spellerX(const char *seed, size_t seedlen, fp_speller_t fp, void *fparg, if (!buf) return NULL; // no matches } + int cost = INT_MAX, ncost; + void *p = NULL, *np; /* Deletions */ memcpy(buf, seed + 1, seedlen); for (size_t i = 0; i < seedlen; i++) { //printf("del buf = '%s'\n", buf); - void *p; if (flag) - p = spellerY(buf, seedlen - 1, fp, fparg, charset, i); + np = spellerY(buf, seedlen - 1, fp, fparg, charset, i, &ncost); else - p = (*fp)(fparg, buf); - if (p) + np = (*fp)(fparg, buf, &ncost); + if (combineSpellerResult(p, cost, np, ncost)) return p; buf[i] = seed[i]; @@ -144,8 +161,7 @@ void *spellerX(const char *seed, size_t seedlen, fp_speller_t fp, void *fparg, buf[i + 1] = seed[i]; //printf("tra buf = '%s'\n", buf); - void *p = (*fp)(fparg, buf); - if (p) + if (combineSpellerResult(p, cost, (*fp)(fparg, buf, &ncost), ncost)) return p; buf[i] = seed[i]; @@ -163,12 +179,11 @@ void *spellerX(const char *seed, size_t seedlen, fp_speller_t fp, void *fparg, buf[i] = *s; //printf("sub buf = '%s'\n", buf); - void *p; if (flag) - p = spellerY(buf, seedlen, fp, fparg, charset, i + 1); + np = spellerY(buf, seedlen, fp, fparg, charset, i + 1, &ncost); else - p = (*fp)(fparg, buf); - if (p) + np = (*fp)(fparg, buf, &ncost); + if (combineSpellerResult(p, cost, np, ncost)) return p; } buf[i] = seed[i]; @@ -183,21 +198,34 @@ void *spellerX(const char *seed, size_t seedlen, fp_speller_t fp, void *fparg, buf[i] = *s; //printf("ins buf = '%s'\n", buf); - void *p; if (flag) - p = spellerY(buf, seedlen + 1, fp, fparg, charset, i + 1); + np = spellerY(buf, seedlen + 1, fp, fparg, charset, i + 1, &ncost); else - p = (*fp)(fparg, buf); - if (p) + np = (*fp)(fparg, buf, &ncost); + if (combineSpellerResult(p, cost, np, ncost)) return p; } buf[i] = seed[i]; // going past end of seed[] is ok, as we hit the 0 } } - return NULL; // didn't find any corrections + return p; // return "best" result } +/************************************************** + * Looks for correct spelling. + * Currently only looks a 'distance' of one from the seed[]. + * This does an exhaustive search, so can potentially be very slow. + * Input: + * seed wrongly spelled word + * fp search function + * fparg argument to search function + * charset character set + * Returns: + * NULL no correct spellings found + * void* value returned by fp() for first possible correct spelling + */ + void *speller(const char *seed, fp_speller_t fp, void *fparg, const char *charset) { size_t seedlen = strlen(seed); @@ -219,9 +247,10 @@ void *speller(const char *seed, fp_speller_t fp, void *fparg, const char *charse #include #include -void *speller_test(void *fparg, const char *s) +void *speller_test(void *fparg, const char *s, int* cost) { //printf("speller_test(%s, %s)\n", fparg, s); + *cost = 0; if (strcmp((char *)fparg, s) == 0) return fparg; return NULL; diff --git a/src/root/speller.h b/src/root/speller.h index b01c5a81f451..bfc6858d8989 100644 --- a/src/root/speller.h +++ b/src/root/speller.h @@ -7,7 +7,7 @@ * https://github.com/D-Programming-Language/dmd/blob/master/src/root/speller.h */ -typedef void *(fp_speller_t)(void *, const char *); +typedef void *(fp_speller_t)(void *, const char *, int*); extern const char idchars[]; diff --git a/src/scope.c b/src/scope.c index 8a9016317e53..c533d5c7c8b5 100644 --- a/src/scope.c +++ b/src/scope.c @@ -363,7 +363,7 @@ Module *Scope::instantiatingModule() return minst ? minst : module; } -Dsymbol *Scope::search(Loc loc, Identifier *ident, Dsymbol **pscopesym) +Dsymbol *Scope::search(Loc loc, Identifier *ident, Dsymbol **pscopesym, int flags) { //printf("Scope::search(%p, '%s')\n", this, ident->toChars()); if (ident == Id::empty) @@ -393,12 +393,12 @@ Dsymbol *Scope::search(Loc loc, Identifier *ident, Dsymbol **pscopesym) continue; //printf("\tlooking in scopesym '%s', kind = '%s'\n", sc->scopesym->toChars(), sc->scopesym->kind()); - if (Dsymbol *s = sc->scopesym->search(loc, ident)) + if (Dsymbol *s = sc->scopesym->search(loc, ident, flags)) { if (ident == Id::length && sc->scopesym->isArrayScopeSymbol() && sc->enclosing && - sc->enclosing->search(loc, ident, NULL)) + sc->enclosing->search(loc, ident, NULL, flags)) { warning(s->loc, "array 'length' hides other 'length' name in outer scope"); } @@ -514,7 +514,7 @@ void Scope::setNoFree() * one with a close spelling. */ -void *scope_search_fp(void *arg, const char *seed) +void *scope_search_fp(void *arg, const char *seed, int* cost) { //printf("scope_search_fp('%s')\n", seed); @@ -532,7 +532,20 @@ void *scope_search_fp(void *arg, const char *seed) Scope *sc = (Scope *)arg; Module::clearCache(); - Dsymbol *s = sc->search(Loc(), id, NULL); + Dsymbol *scopesym = NULL; + Dsymbol *s = sc->search(Loc(), id, &scopesym, IgnoreErrors); + if (s) + { + for (*cost = 0; sc; sc = sc->enclosing, (*cost)++) + if (sc->scopesym == scopesym) + break; + if (scopesym != s->parent) + { + (*cost)++; // got to the symbol through an import + if (s->prot().kind == PROTprivate) + return NULL; + } + } return (void*)s; } diff --git a/src/scope.h b/src/scope.h index ae05dfbbac78..a22579f59765 100644 --- a/src/scope.h +++ b/src/scope.h @@ -145,7 +145,7 @@ struct Scope Module *instantiatingModule(); - Dsymbol *search(Loc loc, Identifier *ident, Dsymbol **pscopesym); + Dsymbol *search(Loc loc, Identifier *ident, Dsymbol **pscopesym, int flags = IgnoreNone); Dsymbol *search_correct(Identifier *ident); Dsymbol *insert(Dsymbol *s); diff --git a/src/traits.c b/src/traits.c index ac151c37b70d..6d9553a7f017 100644 --- a/src/traits.c +++ b/src/traits.c @@ -272,13 +272,14 @@ void initTraitsStringTable() } } -void *trait_search_fp(void *arg, const char *seed) +void *trait_search_fp(void *arg, const char *seed, int* cost) { //printf("trait_search_fp('%s')\n", seed); size_t len = strlen(seed); if (!len) return NULL; + *cost = 0; StringValue *sv = traitsStringTable.lookup(seed, len); return sv ? (void*)sv->ptrvalue : NULL; } diff --git a/test/fail_compilation/imports/spell9644a.d b/test/fail_compilation/imports/spell9644a.d new file mode 100644 index 000000000000..b148ff71895d --- /dev/null +++ b/test/fail_compilation/imports/spell9644a.d @@ -0,0 +1,7 @@ +module imports.spell9644a; + +public import imports.spell9644b; + +int cora; +int pub; +private int priv; diff --git a/test/fail_compilation/imports/spell9644b.d b/test/fail_compilation/imports/spell9644b.d new file mode 100644 index 000000000000..aa6ff76da884 --- /dev/null +++ b/test/fail_compilation/imports/spell9644b.d @@ -0,0 +1,3 @@ +module imports.spell9644b; + +private int prib; diff --git a/test/fail_compilation/spell9644.d b/test/fail_compilation/spell9644.d index b8c9cf027151..f59424f8947e 100644 --- a/test/fail_compilation/spell9644.d +++ b/test/fail_compilation/spell9644.d @@ -4,17 +4,23 @@ /* TEST_OUTPUT: --- -fail_compilation/spell9644.d(21): Error: undefined identifier b -fail_compilation/spell9644.d(22): Error: undefined identifier xx -fail_compilation/spell9644.d(23): Error: undefined identifier cb, did you mean variable ab? -fail_compilation/spell9644.d(24): Error: undefined identifier bc, did you mean variable abc? -fail_compilation/spell9644.d(25): Error: undefined identifier ccc +fail_compilation/spell9644.d(27): Error: undefined identifier b +fail_compilation/spell9644.d(28): Error: undefined identifier xx +fail_compilation/spell9644.d(29): Error: undefined identifier cb, did you mean variable ab? +fail_compilation/spell9644.d(30): Error: undefined identifier bc, did you mean variable abc? +fail_compilation/spell9644.d(31): Error: undefined identifier ccc +fail_compilation/spell9644.d(33): Error: undefined identifier cor2, did you mean variable cor1? +fail_compilation/spell9644.d(34): Error: undefined identifier pua, did you mean variable pub? +fail_compilation/spell9644.d(35): Error: undefined identifier priw --- */ +import imports.spell9644a; + int a; int ab; int abc; +int cor1; int main() { @@ -23,4 +29,8 @@ int main() cast(void)cb; // max distance 1, match cast(void)bc; // max distance 1, match cast(void)ccc; // max distance 2, match + + cast(void)cor2; // max distance 1, match "cor1", but not cora from import (bug 13736) + cast(void)pua; // max distance 1, match "pub" from import + cast(void)priw; // max distance 1, match "priv" from import, but do not report (bug 5839) }