-
Notifications
You must be signed in to change notification settings - Fork 19
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix several problems with symbol protection. #153
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this absolutely needs a lot of tests before I would approve this
@@ -1106,7 +1113,7 @@ private: | |||
} | |||
|
|||
SemanticSymbol* allocateSemanticSymbol(string name, CompletionKind kind, | |||
istring symbolFile, size_t location = 0) | |||
istring symbolFile, size_t location = 0, IdType protection = tok!"public") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think a default value is a bad idea. I would revert this definition, make it deprecated and add another overload with non-optional protection argument. This way we don't get issues with people assuming no protection and also simplify a lot of caller code which currently manually sets acSymbol.protection which isn't covered by the PR yet.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few points to keep in mind:
- I think that this default is a better one than the previous default of
tok!""
, which is much less valid thanpublic
.public
is the default for class members, and I'm pretty sure that it's the default for other things as well, but it's not actually written down in the language spec. allocateSemanticSymbol
andpushSymbol
are both private, so we're not really breaking an API.
I do plan on doing another pass over this code to make more use of this extra argument. In general this module needs a lot of cleanup and documentation.
@@ -848,7 +856,7 @@ private: | |||
} | |||
|
|||
void pushSymbol(string name, CompletionKind kind, istring symbolFile, | |||
size_t location = 0, const Type type = null) | |||
size_t location = 0, const Type type = null, const IdType protection = tok!"public") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this protection argument isn't used
also ditto from previous comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will fix.
let's try to make this file 100% covered with tests |
I made the following addition in tests.d for a small testing solution: /**
* Parses `source`, caches its symbols and compares the the cache content
* with `expected`.
*
* Params:
* source = The source code to test.
* expected = An array of [variable name, protection]
*/
void expectSymbolsAndProtection(const string source, const string[2][] expected,
string file = __FILE_FULL_PATH__, size_t line = __LINE__)
{
import core.exception : AssertError;
import std.array : appender;
import std.exception : enforce;
ModuleCache mcache = createTestModuleCache();
auto pair = generateAutocompleteTrees(source, mcache);
scope(exit) pair.destroy();
string[2][] actual;
void visit(DSymbol* symbol)
{
// filter no protection
// keywords (.init, .min, .max)
// class __vptr, __monitor, etc
// remove empty symbol names (root symbol)
if (symbol.protection
&& symbol.kind != CompletionKind.keyword
&& !symbol.name.data.startsWith("__")
&& symbol.name.data != "classinfo"
&& symbol.name.data.length)
{
actual ~= [symbol.name.data, str(symbol.protection)];
}
foreach(DSymbol* ss; (*symbol)[])
visit(ss);
}
visit(pair.symbol);
enforce!AssertError(actual == expected,
"expected symbols\n[\n\t%(%s\n\t%)\n] but got\n[\n\t%(%s\n\t%)\n]".format(expected, actual),
file, line);
} with a test @("exhaustive protection tests")
unittest
{
q{
import object;
class DefaultFoo {}
public class PublicFoo {}
private struct PrivateStruct
{
T memberMethod(T, alias aliasArg, int intArg, VA...)(short runtimeArg, VA vaarg)
{
return T.init + runtimeArg * vaarg;
}
}
package { enum PackageEnum { enumValue } }
int publicInt;
private int privateInt;
void publicMain() {
int localVariable;
}
}.expectSymbolsAndProtection([
["DefaultFoo", "public"]
["PublicFoo", "public"]
["PrivateStruct", "private"] // <-- this is failing
["*constructor*", "public"]
["memberMethod", "public"]
["T", "public"] // should these symbols have protection?
["aliasArg", "public"] // ditto
["intArg", "public"] // ditto
["VA", "public"] // ditto
["runtimeArg", "public"] // ditto
["vaarg", "public"] // ditto
["PackageEnum", "package"] // <-- this is failing
["enumValue", "public"]
["publicInt", "public"]
["privateInt", "private"]
["publicMain", "public"]
["localVariable", "public"], // should this symbol have protection?
]);
} |
I think that I finally reduced a test case for the root cause of the original DCD issue: struct Indexed
{
static if (true)
{
unittest
{
}
}
private:
}
int indexed()
{
return 0;
} This combination of |
All right. I found it. The problem is that |
I suspect that Edit: It is struct Indexed
{
static if (true)
{
void doStuff() do {}
}
private:
}
int indexed; This causes |
I still do want to do this rework of the symbol creation, but the actual fix for the the DCD issue will come in a separate pull request that fixes the parser contained in dsymbol/conversion/package.d |
moved to dlang-community/DCD#679 |
There were several problems with protection being set on symbols. An example of this is dlang-community/DCD#620.
This adds a few extra asserts, and prevents a lot of cases of symbols being created without any protection being set.