Handle public imports MUCH more efficiently. Fixes #160

This commit is contained in:
Hackerpilot 2014-09-02 17:46:40 -07:00
parent dcd01fba76
commit 0783d92e0d
10 changed files with 196 additions and 78 deletions

View File

@ -2,6 +2,7 @@
all: dmd all: dmd
dmd: dmdserver dmdclient dmd: dmdserver dmdclient
debug: dmdclient debugserver
gdc: gdcserver gdcclient gdc: gdcserver gdcclient
ldc: ldcserver ldcclient ldc: ldcserver ldcclient
@ -83,6 +84,13 @@ DMD_SERVER_FLAGS = -Icontainers/src\
-inline\ -inline\
-ofbin/dcd-server -ofbin/dcd-server
DEBUG_SERVER_FLAGS = -Icontainers/src\
-Imsgpack-d/src\
-Ilibdparse/src\
-wi\
-g\
-ofbin/dcd-server
GDC_SERVER_FLAGS = -Icontainers/src\ GDC_SERVER_FLAGS = -Icontainers/src\
-Imsgpack-d/src\ -Imsgpack-d/src\
-Ilibdparse/src\ -Ilibdparse/src\
@ -108,6 +116,12 @@ dmdserver:
rm -f containers/src/std/allocator.d rm -f containers/src/std/allocator.d
${DMD} ${SERVER_SRC} ${DMD_SERVER_FLAGS} ${DMD} ${SERVER_SRC} ${DMD_SERVER_FLAGS}
debugserver:
mkdir -p bin
rm -f containers/src/std/allocator.d
${DMD} ${SERVER_SRC} ${DEBUG_SERVER_FLAGS}
gdcclient: gdcclient:
mkdir -p bin mkdir -p bin
rm -f containers/src/std/allocator.d rm -f containers/src/std/allocator.d

View File

@ -2,4 +2,4 @@ sonar.projectKey=dcd
sonar.projectName=DCD sonar.projectName=DCD
sonar.projectVersion=1.0 sonar.projectVersion=1.0
sonar.sourceEncoding=UTF-8 sonar.sourceEncoding=UTF-8
sonar.sources=. sonar.sources=src

View File

@ -21,7 +21,6 @@ module actypes;
import std.algorithm; import std.algorithm;
import std.array; import std.array;
import std.container; import std.container;
//import std.stdio;
import std.typecons; import std.typecons;
import std.allocator; import std.allocator;
@ -55,6 +54,9 @@ struct ACSymbol
{ {
public: public:
/**
* Copying is disabled.
*/
@disable this(); @disable this();
/** /**
@ -115,12 +117,18 @@ public:
*/ */
ACSymbol*[] getPartsByName(string name) ACSymbol*[] getPartsByName(string name)
{ {
import std.range : chain;
ACSymbol s = ACSymbol(name); ACSymbol s = ACSymbol(name);
auto er = parts.equalRange(&s); ACSymbol p = ACSymbol(IMPORT_SYMBOL_NAME);
if (er.empty) auto app = appender!(ACSymbol*[])();
return array(aliasThisParts.equalRange(&s)); foreach (part; parts.equalRange(&s))
else app.put(part);
return array(er); foreach (extra; extraSymbols.equalRange(&s))
app.put(extra.getPartsByName(name));
foreach (im; parts.equalRange(&p))
foreach (part; im.type.parts.equalRange(&s))
app.put(part);
return app.data();
} }
/** /**
@ -231,11 +239,16 @@ struct Scope
if (s is null) if (s is null)
return []; return [];
UnrolledList!(ACSymbol*) symbols; UnrolledList!(ACSymbol*) symbols;
symbols.insert(s.symbols[]); Scope* sc = s;
Scope* sc = s.parent;
while (sc !is null) while (sc !is null)
{ {
symbols.insert(sc.symbols[]); foreach (item; sc.symbols[])
{
if (item.kind == CompletionKind.importSymbol) foreach (i; item.type.parts[])
symbols.insert(i);
else
symbols.insert(item);
}
sc = sc.parent; sc = sc.parent;
} }
return array(symbols[]); return array(symbols[]);
@ -253,7 +266,18 @@ struct Scope
ACSymbol s = ACSymbol(name); ACSymbol s = ACSymbol(name);
auto er = symbols.equalRange(&s); auto er = symbols.equalRange(&s);
if (!er.empty) if (!er.empty)
return cast(typeof(return)) array(er); return array(er);
ACSymbol ir = ACSymbol(IMPORT_SYMBOL_NAME);
auto r = symbols.equalRange(&ir);
if (!r.empty)
{
auto app = appender!(ACSymbol*[])();
foreach (e; r)
foreach (importedSymbol; e.type.parts.equalRange(&s))
app.put(importedSymbol);
if (app.data.length > 0)
return app.data;
}
if (parent is null) if (parent is null)
return []; return [];
return parent.getSymbolsByName(name); return parent.getSymbolsByName(name);
@ -275,6 +299,9 @@ struct Scope
return s.getSymbolsByName(name); return s.getSymbolsByName(name);
} }
/**
* Returns an array of symbols that are present at global scope
*/
ACSymbol*[] getSymbolsAtGlobalScope(string name) ACSymbol*[] getSymbolsAtGlobalScope(string name)
{ {
if (parent !is null) if (parent !is null)
@ -344,6 +371,16 @@ TTree!(ACSymbol*, true, "a < b", false) classSymbols;
private immutable(string[24]) builtinTypeNames; private immutable(string[24]) builtinTypeNames;
/**
* Name given to the public import symbol. Its value is "public" because this
* is not a valid identifier. This is initialized to an interned string during
* static construction.
*/
immutable string IMPORT_SYMBOL_NAME;
/**
* Translates the IDs for built-in types into an interned string.
*/
string getBuiltinTypeName(IdType id) string getBuiltinTypeName(IdType id)
{ {
switch (id) switch (id)
@ -407,6 +444,8 @@ static this()
builtinTypeNames[22] = internString("cfloat"); builtinTypeNames[22] = internString("cfloat");
builtinTypeNames[23] = internString("creal"); builtinTypeNames[23] = internString("creal");
IMPORT_SYMBOL_NAME = internString("public");
auto bool_ = allocate!ACSymbol(Mallocator.it, "bool", CompletionKind.keyword); auto bool_ = allocate!ACSymbol(Mallocator.it, "bool", CompletionKind.keyword);
auto int_ = allocate!ACSymbol(Mallocator.it, "int", CompletionKind.keyword); auto int_ = allocate!ACSymbol(Mallocator.it, "int", CompletionKind.keyword);

View File

@ -295,6 +295,7 @@ AutocompleteResponse parenCompletion(T)(T beforeTokens,
bool isSelectiveImport(T)(T tokens) bool isSelectiveImport(T)(T tokens)
{ {
assert (tokens.length > 1);
size_t i = tokens.length - 1; size_t i = tokens.length - 1;
if (!(tokens[i] == tok!":" || tokens[i] == tok!",")) if (!(tokens[i] == tok!":" || tokens[i] == tok!","))
return false; return false;
@ -391,7 +392,7 @@ body
auto symbols = ModuleCache.getSymbolsInModule(ModuleCache.resolveImportLoctation(path)); auto symbols = ModuleCache.getSymbolsInModule(ModuleCache.resolveImportLoctation(path));
import containers.hashset; import containers.hashset;
HashSet!string h; HashSet!string h;
foreach (s; symbols) foreach (s; symbols.parts[])
{ {
auto a = ACSymbol(s.name); auto a = ACSymbol(s.name);
if (!builtinSymbols.contains(&a) && !h.contains(s.name)) if (!builtinSymbols.contains(&a) && !h.contains(s.name))
@ -630,7 +631,8 @@ void setCompletions(T)(ref AutocompleteResponse response,
} }
TTree!(ACSymbol*, true, "a < b", false) parts; TTree!(ACSymbol*, true, "a < b", false) parts;
parts.insert(symbols[0].parts[]); parts.insert(symbols[0].parts[]);
parts.insert(symbols[0].aliasThisParts[]); foreach (s; symbols[0].extraSymbols[])
parts.insert(s.parts[]);
foreach (s; parts[].filter!(a => a.name !is null foreach (s; parts[].filter!(a => a.name !is null
&& a.name.length > 0 && a.name[0] != '*' && a.name.length > 0 && a.name[0] != '*'
&& (partial is null ? true : a.name.toUpper().startsWith(partial.toUpper())) && (partial is null ? true : a.name.toUpper().startsWith(partial.toUpper()))

View File

@ -292,12 +292,11 @@ final class FirstPass : ASTVisitor
rootSymbol = currentSymbol; rootSymbol = currentSymbol;
currentScope = allocate!Scope(semanticAllocator, 0, size_t.max); currentScope = allocate!Scope(semanticAllocator, 0, size_t.max);
auto i = allocate!ImportInformation(semanticAllocator); auto i = allocate!ImportInformation(semanticAllocator);
i.modulePath = "object"; i.modulePath = internString("object");
i.importParts.insert("object"); i.importParts.insert(i.modulePath);
currentScope.importInformation.insert(i); currentScope.importInformation.insert(i);
moduleScope = currentScope; moduleScope = currentScope;
mod.accept(this); mod.accept(this);
assert (currentSymbol.acSymbol.name is null);
} }
override void visit(const EnumDeclaration dec) override void visit(const EnumDeclaration dec)
@ -328,10 +327,7 @@ final class FirstPass : ASTVisitor
override void visit(const ModuleDeclaration moduleDeclaration) override void visit(const ModuleDeclaration moduleDeclaration)
{ {
// Log.trace(__FUNCTION__, " ", typeof(dec).stringof); // Log.trace(__FUNCTION__, " ", typeof(dec).stringof);
foreach (identifier; moduleDeclaration.moduleName.identifiers) rootSymbol.acSymbol.name = internString(moduleDeclaration.moduleName.identifiers[$ - 1].text);
{
moduleName.insert(internString(identifier.text));
}
} }
override void visit(const StructBody structBody) override void visit(const StructBody structBody)
@ -616,9 +612,6 @@ private:
/// Current protection type /// Current protection type
IdType protection; IdType protection;
/// Package and module name
UnrolledList!string moduleName;
/// Current scope /// Current scope
Scope* currentScope; Scope* currentScope;

View File

@ -24,6 +24,7 @@ import semantic;
import messages; import messages;
import std.allocator; import std.allocator;
import stupidlog; import stupidlog;
import string_interning;
/** /**
* Second pass handles the following: * Second pass handles the following:
@ -68,32 +69,35 @@ private:
} }
} }
/**
* Creates package symbols as necessary to contain the given module symbol
*/
ACSymbol* createImportSymbols(ImportInformation* info, Scope* currentScope, ACSymbol* createImportSymbols(ImportInformation* info, Scope* currentScope,
ACSymbol*[] moduleSymbols) ACSymbol* moduleSymbol)
in in
{ {
assert (info !is null); assert (info !is null);
foreach (s; moduleSymbols) assert (moduleSymbol !is null);
assert (s !is null);
} }
body body
{ {
immutable string firstPart = info.importParts[].front; immutable string firstPart = info.importParts[].front;
// Log.trace("firstPart = ", firstPart);
ACSymbol*[] symbols = currentScope.getSymbolsByName(firstPart); ACSymbol*[] symbols = currentScope.getSymbolsByName(firstPart);
immutable bool found = symbols.length > 0; ACSymbol* firstSymbol = void;
ACSymbol* firstSymbol = found if (symbols.length > 0)
? symbols[0] : allocate!ACSymbol(symbolAllocator, firstPart, firstSymbol = symbols[0];
else
firstSymbol = allocate!ACSymbol(symbolAllocator, firstPart,
CompletionKind.packageName); CompletionKind.packageName);
if (!found)
currentScope.symbols.insert(firstSymbol); currentScope.symbols.insert(firstSymbol);
// Log.trace(firstSymbol.name);
ACSymbol* currentSymbol = firstSymbol; ACSymbol* currentSymbol = firstSymbol;
size_t i = 0; size_t i = 0;
foreach (string importPart; info.importParts[]) foreach (string importPart; info.importParts[])
{ {
if (i++ == 0) if (i++ == 0)
continue; continue;
if (i + 2 >= info.importParts.length) // Skip the last item as it's the module name
break;
symbols = currentSymbol.getPartsByName(importPart); symbols = currentSymbol.getPartsByName(importPart);
ACSymbol* s = symbols.length > 0 ACSymbol* s = symbols.length > 0
? cast(ACSymbol*) symbols[0] : allocate!ACSymbol(symbolAllocator, ? cast(ACSymbol*) symbols[0] : allocate!ACSymbol(symbolAllocator,
@ -101,9 +105,7 @@ private:
currentSymbol.parts.insert(s); currentSymbol.parts.insert(s);
currentSymbol = s; currentSymbol = s;
} }
currentSymbol.kind = CompletionKind.moduleName; currentSymbol.parts.insert(moduleSymbol);
currentSymbol.parts.insert(moduleSymbols);
// Log.trace(currentSymbol.name);
return currentSymbol; return currentSymbol;
} }
@ -114,19 +116,21 @@ private:
foreach (importInfo; currentScope.importInformation[]) foreach (importInfo; currentScope.importInformation[])
{ {
string location = ModuleCache.resolveImportLoctation(importInfo.modulePath); string location = ModuleCache.resolveImportLoctation(importInfo.modulePath);
ACSymbol*[] symbols = location is null ? [] : ModuleCache.getSymbolsInModule(location); ACSymbol* symbol = location is null ? null : ModuleCache.getSymbolsInModule(location);
ACSymbol* moduleSymbol = createImportSymbols(importInfo, currentScope, symbols); if (symbol is null)
currentScope.symbols.insert(moduleSymbol); continue;
currentScope.symbols.insert(symbols); ACSymbol* moduleSymbol = createImportSymbols(importInfo, currentScope, symbol);
currentScope.symbols.insert(symbol.parts[]);
if (importInfo.importedSymbols.length == 0) if (importInfo.importedSymbols.length == 0)
{ {
if (importInfo.isPublic && currentScope.parent is null) if (importInfo.isPublic && currentScope.parent is null)
{ {
rootSymbol.acSymbol.parts.insert(symbols); rootSymbol.acSymbol.parts.insert(allocate!ACSymbol(symbolAllocator,
IMPORT_SYMBOL_NAME, CompletionKind.importSymbol, symbol));
} }
continue; continue;
} }
symbolLoop: foreach (symbol; symbols) symbolLoop: foreach (sym; symbol.parts[])
{ {
foreach (tup; importInfo.importedSymbols[]) foreach (tup; importInfo.importedSymbols[])
{ {
@ -135,15 +139,13 @@ private:
if (tup[1] !is null) if (tup[1] !is null)
{ {
ACSymbol* s = allocate!ACSymbol(symbolAllocator, tup[1], ACSymbol* s = allocate!ACSymbol(symbolAllocator, tup[1],
symbol.kind, symbol.type); sym.kind, sym.type);
// TODO: Compiler gets confused here, so cast the types. s.parts.insert(sym.parts[]);
s.parts.insert(symbol.parts[]); s.callTip = sym.callTip;
// TODO: Re-format callTip with new name? s.doc = sym.doc;
s.callTip = symbol.callTip; s.qualifier = sym.qualifier;
s.doc = symbol.doc; s.location = sym.location;
s.qualifier = symbol.qualifier; s.symbolFile = sym.symbolFile;
s.location = symbol.location;
s.symbolFile = symbol.symbolFile;
currentScope.symbols.insert(s); currentScope.symbols.insert(s);
moduleSymbol.parts.insert(s); moduleSymbol.parts.insert(s);
if (importInfo.isPublic && currentScope.parent is null) if (importInfo.isPublic && currentScope.parent is null)
@ -151,10 +153,10 @@ private:
} }
else else
{ {
moduleSymbol.parts.insert(symbol); moduleSymbol.parts.insert(sym);
currentScope.symbols.insert(symbol); currentScope.symbols.insert(sym);
if (importInfo.isPublic && currentScope.parent is null) if (importInfo.isPublic && currentScope.parent is null)
rootSymbol.acSymbol.parts.insert(symbol); rootSymbol.acSymbol.parts.insert(sym);
} }
} }
} }

View File

@ -92,6 +92,7 @@ private:
case assocArray: case assocArray:
case templateName: case templateName:
case mixinTemplateName: case mixinTemplateName:
case importSymbol:
break; break;
} }
@ -145,7 +146,7 @@ private:
auto parts = currentSymbol.acSymbol.getPartsByName(aliasThis); auto parts = currentSymbol.acSymbol.getPartsByName(aliasThis);
if (parts.length == 0 || parts[0].type is null) if (parts.length == 0 || parts[0].type is null)
continue; continue;
currentSymbol.acSymbol.aliasThisParts.insert(parts[0].type.parts[]); currentSymbol.acSymbol.aliasThisParts.insert(parts[0].type);
} }
} }

54
src/dscanner-report.json Normal file
View File

@ -0,0 +1,54 @@
{
"issues": [
{
"key": "dscanner.suspicious.incomplete_operator_overloading",
"fileName": "src/modulecache.d",
"line": 46,
"column": 16,
"message": "'CacheEntry' has method 'opCmp', but not 'opEquals'."
},
{
"key": "dscanner.suspicious.length_subtraction",
"fileName": "src/autocomplete.d",
"line": 298,
"column": 20,
"message": "Avoid subtracting from '.length' as it may be unsigned."
},
{
"key": "dscanner.suspicious.length_subtraction",
"fileName": "src/autocomplete.d",
"line": 357,
"column": 26,
"message": "Avoid subtracting from '.length' as it may be unsigned."
},
{
"key": "dscanner.suspicious.length_subtraction",
"fileName": "src/autocomplete.d",
"line": 442,
"column": 68,
"message": "Avoid subtracting from '.length' as it may be unsigned."
},
{
"key": "dscanner.suspicious.length_subtraction",
"fileName": "src/autocomplete.d",
"line": 515,
"column": 12,
"message": "Avoid subtracting from '.length' as it may be unsigned."
},
{
"key": "dscanner.suspicious.length_subtraction",
"fileName": "src/autocomplete.d",
"line": 736,
"column": 26,
"message": "Avoid subtracting from '.length' as it may be unsigned."
}
],
"interfaceCount": 0,
"classCount": 3,
"functionCount": 120,
"templateCount": 0,
"structCount": 11,
"statementCount": 1718,
"lineOfCodeCount": 2180,
"undocumentedPublicSymbols": 0
}

View File

@ -27,6 +27,10 @@ enum CompletionKind : char
/// be returned in a completion response. /// be returned in a completion response.
dummy = '?', dummy = '?',
/// Import symbol. This is used internally and will never
/// be returned in a completion response.
importSymbol = '*',
/// class names /// class names
className = 'c', className = 'c',

View File

@ -45,17 +45,27 @@ import messages;
private struct CacheEntry private struct CacheEntry
{ {
ACSymbol*[] symbols; ACSymbol* symbol;
SysTime modificationTime; SysTime modificationTime;
string path; string path;
int opCmp(ref const CacheEntry other) const int opCmp(ref const CacheEntry other) const
{ {
int r = path > other.path;
if (path < other.path) if (path < other.path)
return -1; return -1;
if (path > other.path) return r;
return 1; }
return 0;
bool opEquals(ref const CacheEntry other) const
{
return path == other.path;
}
size_t toHash() const
{
import core.internal.hash : hashOf;
return hashOf(path);
} }
void opAssign(ref const CacheEntry other) void opAssign(ref const CacheEntry other)
@ -64,6 +74,9 @@ private struct CacheEntry
} }
} }
/**
* Returns: true if a file exists at the given path.
*/
bool existanceCheck(A)(A path) bool existanceCheck(A)(A path)
{ {
if (path.exists()) if (path.exists())
@ -84,10 +97,6 @@ struct ModuleCache
{ {
@disable this(); @disable this();
static void clear()
{
}
/** /**
* Adds the given path to the list of directories checked for imports * Adds the given path to the list of directories checked for imports
*/ */
@ -108,13 +117,16 @@ struct ModuleCache
} }
} }
/// TODO: Implement
static void clear() {}
/** /**
* Params: * Params:
* moduleName = the name of the module in "a/b/c" form * moduleName = the name of the module in "a/b/c" form
* Returns: * Returns:
* The symbols defined in the given module * The symbols defined in the given module
*/ */
static ACSymbol*[] getSymbolsInModule(string location) static ACSymbol* getSymbolsInModule(string location)
{ {
import string_interning; import string_interning;
assert (location !is null); assert (location !is null);
@ -124,8 +136,8 @@ struct ModuleCache
e.path = location; e.path = location;
auto r = cache.equalRange(&e); auto r = cache.equalRange(&e);
if (!r.empty) if (!r.empty)
return r.front.symbols; return r.front.symbol;
return []; return null;
} }
string cachedLocation = internString(location); string cachedLocation = internString(location);
@ -134,9 +146,7 @@ struct ModuleCache
recursionGuard.insert(cachedLocation); recursionGuard.insert(cachedLocation);
ACSymbol* symbol;
ACSymbol*[] symbols;
// try // try
// { // {
import std.stdio; import std.stdio;
@ -144,7 +154,7 @@ struct ModuleCache
File f = File(cachedLocation); File f = File(cachedLocation);
immutable fileSize = cast(size_t)f.size; immutable fileSize = cast(size_t)f.size;
if (fileSize == 0) if (fileSize == 0)
return symbols; return null;
ubyte[] source = cast(ubyte[]) Mallocator.it.allocate(fileSize); ubyte[] source = cast(ubyte[]) Mallocator.it.allocate(fileSize);
f.rawRead(source); f.rawRead(source);
LexerConfig config; LexerConfig config;
@ -156,6 +166,8 @@ struct ModuleCache
config, &parseStringCache); config, &parseStringCache);
Mallocator.it.deallocate(source); Mallocator.it.deallocate(source);
// StopWatch sw;
// sw.start();
Module m = parseModuleSimple(tokens[], cachedLocation, semanticAllocator); Module m = parseModuleSimple(tokens[], cachedLocation, semanticAllocator);
assert (symbolAllocator); assert (symbolAllocator);
@ -163,20 +175,17 @@ struct ModuleCache
semanticAllocator); semanticAllocator);
first.run(); first.run();
// Log.trace(location, " finished in ", sw.peek.msecs, "msecs");
SecondPass second = SecondPass(first); SecondPass second = SecondPass(first);
second.run(); second.run();
ThirdPass third = ThirdPass(second, cachedLocation); ThirdPass third = ThirdPass(second, cachedLocation);
third.run(); third.run();
symbols = cast(ACSymbol*[]) Mallocator.it.allocate( symbol = third.rootSymbol.acSymbol;
third.rootSymbol.acSymbol.parts.length * (ACSymbol*).sizeof);
size_t i = 0;
foreach (part; third.rootSymbol.acSymbol.parts[])
symbols[i++] = part;
typeid(Scope).destroy(third.moduleScope); typeid(Scope).destroy(third.moduleScope);
typeid(SemanticSymbol).destroy(third.rootSymbol);
symbolsAllocated += first.symbolsAllocated; symbolsAllocated += first.symbolsAllocated;
// } // }
// catch (Exception ex) // catch (Exception ex)
@ -187,11 +196,11 @@ struct ModuleCache
SysTime access; SysTime access;
SysTime modification; SysTime modification;
getTimes(cachedLocation, access, modification); getTimes(cachedLocation, access, modification);
CacheEntry* c = allocate!CacheEntry(Mallocator.it, symbols, CacheEntry* c = allocate!CacheEntry(Mallocator.it, symbol,
modification, cachedLocation); modification, cachedLocation);
cache.insert(c); cache.insert(c);
recursionGuard.remove(cachedLocation); recursionGuard.remove(cachedLocation);
return symbols; return symbol;
} }
/** /**