dmd/compiler/test/unit/compilable/searching.d
2023-12-08 14:56:03 +08:00

183 lines
3.4 KiB
D

// See ../../README.md for information about DMD unit tests.
//
// Verify that searches using Dsymbol.search inside of templates respect
// the IgnoreErrors flag (instead of raising an error)
module compilable.searching;
import support : afterEach, beforeEach, compiles;
import dmd.dsymbol;
import dmd.dsymbolsem;
import dmd.dclass : ClassDeclaration;
import dmd.declaration : VarDeclaration;
import dmd.dtemplate : TemplateDeclaration;
import dmd.globals : global;
import dmd.identifier : Identifier;
import dmd.location;
@beforeEach initializeFrontend()
{
import dmd.frontend : initDMD;
initDMD();
}
@afterEach deinitializeFrontend()
{
import dmd.frontend : deinitializeDMD;
deinitializeDMD();
}
@("Test searching templated class members")
unittest
{
doTest(q{
class Clazz(T)
{
T member;
}
}, "Clazz");
}
@("Test searching templated struct members")
unittest
{
doTest(q{
class Structure(T)
{
T member;
}
}, "Structure");
}
@("Test searching templated namespace members")
unittest
{
doTest(q{
template Namespace(T)
{
extern(C++, Namespace)
{
T member;
}
}
}, "Namespace");
}
@("Test searching templated enum members")
unittest
{
doTest(q{
template Enumeration(T)
{
enum Enumeration : T
{
member
}
}
}, "Enumeration");
}
@("Test searching templated alias")
unittest
{
doTest(q{
alias Alias(T) = int;
}, "Alias");
}
@("Test searching templated import")
unittest
{
doTest(q{
template Import(T)
{
import object;
}
}, "Import");
}
@("Test searching templated renamed import")
unittest
{
doTest(q{
template Import(T)
{
import core.stdc.stdint : member = int32_t;
}
}, "Import");
}
private:
/**
* Compiles `code` and searches for `symbol` as well as it's member `member`.
*
* `symbol` must be found and the fronted may never raise errors because this
* method uses the `IgnoreErrors` flag.
*/
void doTest(const string code, const string symbol, const string member = "member")
{
auto res = compiles(code);
assert(res, res.toString());
auto mod = cast() res.module_;
auto td = find!TemplateDeclaration(mod, symbol);
// Search doesn't work on uninstantiated templates
assert(td.members);
assert(td.members.length == 1);
auto cl = (*td.members)[0];
find!VarDeclaration(cl, member, true);
}
/**
* Wrapper for `Dsymbol.search` that finds an AST node.
*
* Params:
* T = expected type of the node
* name = name of the symbol
* allowMissing = search is allowed yield no results
*
* Returns: the symbol or `null` if `allowMissing` is true
* (otherwise triggers an assertion failure)
*/
T find(T)(Dsymbol sym, string name, bool allowMissing = false)
{
Dsymbol found = findSymbol(sym, name, allowMissing);
if (allowMissing && !found)
return null;
T res = mixin("found.is" ~ T.stringof);
assert(res, found.toString() ~ " is not a " ~ T.stringof);
return res;
}
/// ditto
Dsymbol findSymbol(Dsymbol sym, string name, bool allowMissing = false)
{
assert(sym, "Missing symbol while searching for: " ~ name);
const oldErrors = global.errors;
Identifier id = Identifier.idPool(name);
Dsymbol found = sym.search(Loc.initial, id, SearchOpt.ignoreErrors);
assert(global.errors == oldErrors, "Searching " ~ name ~ " caused errors!");
assert(allowMissing || found, name ~ " not found!");
return found;
}