Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions src/dsymbol.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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)
Expand Down Expand Up @@ -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++)
Expand All @@ -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;
Expand Down
95 changes: 62 additions & 33 deletions src/root/speller.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <limits.h>

#if __sun || _MSC_VER
#include <alloca.h>
Expand All @@ -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;
Expand All @@ -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;
}

Expand All @@ -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);
Expand All @@ -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,
Expand All @@ -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];
Expand All @@ -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];
Expand All @@ -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];
Expand All @@ -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);
Expand All @@ -219,9 +247,10 @@ void *speller(const char *seed, fp_speller_t fp, void *fparg, const char *charse
#include <string.h>
#include <assert.h>

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;
Expand Down
2 changes: 1 addition & 1 deletion src/root/speller.h
Original file line number Diff line number Diff line change
Expand Up @@ -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[];

Expand Down
23 changes: 18 additions & 5 deletions src/scope.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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");
}
Expand Down Expand Up @@ -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);

Expand All @@ -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;
}

Expand Down
2 changes: 1 addition & 1 deletion src/scope.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
3 changes: 2 additions & 1 deletion src/traits.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
7 changes: 7 additions & 0 deletions test/fail_compilation/imports/spell9644a.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module imports.spell9644a;

public import imports.spell9644b;

int cora;
int pub;
private int priv;
3 changes: 3 additions & 0 deletions test/fail_compilation/imports/spell9644b.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module imports.spell9644b;

private int prib;
20 changes: 15 additions & 5 deletions test/fail_compilation/spell9644.d
Original file line number Diff line number Diff line change
Expand Up @@ -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()
{
Expand All @@ -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)
}