compiler: Record each import as a distinct alias.
This patch introduces the Package_alias class which is a finer representation of the different between a package and the aliases it is imported under. Each alias keeps track of the location of its import statement and how many times that alias has been used. This allows the gofrontend to report when a specific import has not been used even if a symbol from the package has been used by another import. Fixes golang/go#12326. Reviewed-on: https://go-review.googlesource.com/14259 From-SVN: r228550
This commit is contained in:
parent
ce9f2dc532
commit
c12df35927
@ -1,4 +1,4 @@
|
||||
d8150af96de991fb79b1bf65ae982a860552c492
|
||||
3039d79149901d25d89c2412bdd8684f3cbcd09e
|
||||
|
||||
The first line of this file holds the git revision number of the last
|
||||
merge done from the gofrontend repository.
|
||||
|
@ -516,7 +516,6 @@ Gogo::import_package(const std::string& filename,
|
||||
{
|
||||
Package* package = p->second;
|
||||
package->set_location(location);
|
||||
package->set_is_imported();
|
||||
std::string ln = local_name;
|
||||
bool is_ln_exported = is_local_name_exported;
|
||||
if (ln.empty())
|
||||
@ -525,7 +524,9 @@ Gogo::import_package(const std::string& filename,
|
||||
go_assert(!ln.empty());
|
||||
is_ln_exported = Lex::is_exported_name(ln);
|
||||
}
|
||||
if (ln == ".")
|
||||
if (ln == "_")
|
||||
;
|
||||
else if (ln == ".")
|
||||
{
|
||||
Bindings* bindings = package->bindings();
|
||||
for (Bindings::const_declarations_iterator p =
|
||||
@ -533,11 +534,12 @@ Gogo::import_package(const std::string& filename,
|
||||
p != bindings->end_declarations();
|
||||
++p)
|
||||
this->add_dot_import_object(p->second);
|
||||
std::string dot_alias = "." + package->package_name();
|
||||
package->add_alias(dot_alias, location);
|
||||
}
|
||||
else if (ln == "_")
|
||||
package->set_uses_sink_alias();
|
||||
else
|
||||
{
|
||||
package->add_alias(ln, location);
|
||||
ln = this->pack_hidden_name(ln, is_ln_exported);
|
||||
this->package_->bindings()->add_package(ln, package);
|
||||
}
|
||||
@ -563,7 +565,6 @@ Gogo::import_package(const std::string& filename,
|
||||
"being compiled (see -fgo-pkgpath option)"));
|
||||
|
||||
this->imports_.insert(std::make_pair(filename, package));
|
||||
package->set_is_imported();
|
||||
}
|
||||
|
||||
delete stream;
|
||||
@ -1544,7 +1545,10 @@ Gogo::lookup(const std::string& name, Named_object** pfunction) const
|
||||
if (ret != NULL)
|
||||
{
|
||||
if (ret->package() != NULL)
|
||||
ret->package()->note_usage();
|
||||
{
|
||||
std::string dot_alias = "." + ret->package()->package_name();
|
||||
ret->package()->note_usage(dot_alias);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
@ -1594,10 +1598,14 @@ Gogo::add_imported_package(const std::string& real_name,
|
||||
|
||||
*padd_to_globals = false;
|
||||
|
||||
if (alias_arg == ".")
|
||||
*padd_to_globals = true;
|
||||
else if (alias_arg == "_")
|
||||
ret->set_uses_sink_alias();
|
||||
if (alias_arg == "_")
|
||||
;
|
||||
else if (alias_arg == ".")
|
||||
{
|
||||
*padd_to_globals = true;
|
||||
std::string dot_alias = "." + real_name;
|
||||
ret->add_alias(dot_alias, location);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string alias = alias_arg;
|
||||
@ -1606,6 +1614,7 @@ Gogo::add_imported_package(const std::string& real_name,
|
||||
alias = real_name;
|
||||
is_alias_exported = Lex::is_exported_name(alias);
|
||||
}
|
||||
ret->add_alias(alias, location);
|
||||
alias = this->pack_hidden_name(alias, is_alias_exported);
|
||||
Named_object* no = this->package_->bindings()->add_package(alias, ret);
|
||||
if (!no->is_package())
|
||||
@ -2356,15 +2365,30 @@ Gogo::clear_file_scope()
|
||||
++p)
|
||||
{
|
||||
Package* package = p->second;
|
||||
if (package != this->package_
|
||||
&& package->is_imported()
|
||||
&& !package->used()
|
||||
&& !package->uses_sink_alias()
|
||||
&& !quiet)
|
||||
error_at(package->location(), "imported and not used: %s",
|
||||
Gogo::message_name(package->package_name()).c_str());
|
||||
package->clear_is_imported();
|
||||
package->clear_uses_sink_alias();
|
||||
if (package != this->package_ && !quiet)
|
||||
{
|
||||
for (Package::Aliases::const_iterator p1 = package->aliases().begin();
|
||||
p1 != package->aliases().end();
|
||||
++p1)
|
||||
{
|
||||
if (!p1->second->used())
|
||||
{
|
||||
// Give a more refined error message if the alias name is known.
|
||||
std::string pkg_name = package->package_name();
|
||||
if (p1->first != pkg_name && p1->first[0] != '.')
|
||||
{
|
||||
error_at(p1->second->location(),
|
||||
"imported and not used: %s as %s",
|
||||
Gogo::message_name(pkg_name).c_str(),
|
||||
Gogo::message_name(p1->first).c_str());
|
||||
}
|
||||
else
|
||||
error_at(p1->second->location(),
|
||||
"imported and not used: %s",
|
||||
Gogo::message_name(pkg_name).c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
package->clear_used();
|
||||
}
|
||||
}
|
||||
@ -7741,8 +7765,7 @@ Package::Package(const std::string& pkgpath,
|
||||
const std::string& pkgpath_symbol, Location location)
|
||||
: pkgpath_(pkgpath), pkgpath_symbol_(pkgpath_symbol),
|
||||
package_name_(), bindings_(new Bindings(NULL)), priority_(0),
|
||||
location_(location), used_(false), is_imported_(false),
|
||||
uses_sink_alias_(false)
|
||||
location_(location)
|
||||
{
|
||||
go_assert(!pkgpath.empty());
|
||||
|
||||
@ -7796,6 +7819,16 @@ Package::set_priority(int priority)
|
||||
this->priority_ = priority;
|
||||
}
|
||||
|
||||
// Note that symbol from this package was and qualified by ALIAS.
|
||||
|
||||
void
|
||||
Package::note_usage(const std::string& alias) const
|
||||
{
|
||||
Aliases::const_iterator p = this->aliases_.find(alias);
|
||||
go_assert(p != this->aliases_.end());
|
||||
p->second->note_usage();
|
||||
}
|
||||
|
||||
// Forget a given usage. If forgetting this usage means this package becomes
|
||||
// unused, report that error.
|
||||
|
||||
@ -7811,7 +7844,7 @@ Package::forget_usage(Expression* usage) const
|
||||
|
||||
if (this->fake_uses_.empty())
|
||||
error_at(this->location(), "imported and not used: %s",
|
||||
Gogo::message_name(this->package_name()).c_str());
|
||||
Gogo::message_name(this->package_name()).c_str());
|
||||
}
|
||||
|
||||
// Clear the used field for the next file. If the only usages of this package
|
||||
@ -7820,10 +7853,26 @@ Package::forget_usage(Expression* usage) const
|
||||
void
|
||||
Package::clear_used()
|
||||
{
|
||||
if (this->used_ > this->fake_uses_.size())
|
||||
std::string dot_alias = "." + this->package_name();
|
||||
Aliases::const_iterator p = this->aliases_.find(dot_alias);
|
||||
if (p != this->aliases_.end() && p->second->used() > this->fake_uses_.size())
|
||||
this->fake_uses_.clear();
|
||||
|
||||
this->used_ = 0;
|
||||
this->aliases_.clear();
|
||||
}
|
||||
|
||||
Package_alias*
|
||||
Package::add_alias(const std::string& alias, Location location)
|
||||
{
|
||||
Aliases::const_iterator p = this->aliases_.find(alias);
|
||||
if (p == this->aliases_.end())
|
||||
{
|
||||
std::pair<Aliases::iterator, bool> ret;
|
||||
ret = this->aliases_.insert(std::make_pair(alias,
|
||||
new Package_alias(location)));
|
||||
p = ret.first;
|
||||
}
|
||||
return p->second;
|
||||
}
|
||||
|
||||
// Determine types of constants. Everything else in a package
|
||||
|
@ -2771,6 +2771,37 @@ class Unnamed_label
|
||||
Blabel* blabel_;
|
||||
};
|
||||
|
||||
// An alias for an imported package.
|
||||
|
||||
class Package_alias
|
||||
{
|
||||
public:
|
||||
Package_alias(Location location)
|
||||
: location_(location), used_(0)
|
||||
{ }
|
||||
|
||||
// The location of the import statement.
|
||||
Location
|
||||
location()
|
||||
{ return this->location_; }
|
||||
|
||||
// How many symbols from the package were used under this alias.
|
||||
size_t
|
||||
used() const
|
||||
{ return this->used_; }
|
||||
|
||||
// Note that some symbol was used under this alias.
|
||||
void
|
||||
note_usage()
|
||||
{ this->used_++; }
|
||||
|
||||
private:
|
||||
// The location of the import statement.
|
||||
Location location_;
|
||||
// The amount of times some name from this package was used under this alias.
|
||||
size_t used_;
|
||||
};
|
||||
|
||||
// An imported package.
|
||||
|
||||
class Package
|
||||
@ -2793,7 +2824,7 @@ class Package
|
||||
void
|
||||
set_pkgpath_symbol(const std::string&);
|
||||
|
||||
// Return the location of the import statement.
|
||||
// Return the location of the most recent import statement.
|
||||
Location
|
||||
location() const
|
||||
{ return this->location_; }
|
||||
@ -2829,15 +2860,18 @@ class Package
|
||||
bindings()
|
||||
{ return this->bindings_; }
|
||||
|
||||
// Whether some symbol from the package was used.
|
||||
bool
|
||||
used() const
|
||||
{ return this->used_ > 0; }
|
||||
// Type used to map import names to package aliases.
|
||||
typedef std::map<std::string, Package_alias*> Aliases;
|
||||
|
||||
// Note that some symbol from this package was used.
|
||||
// Return the set of package aliases.
|
||||
const Aliases&
|
||||
aliases() const
|
||||
{ return this->aliases_; }
|
||||
|
||||
// Note that some symbol from this package was used and qualified by ALIAS.
|
||||
// For dot imports, the ALIAS should be ".PACKAGE_NAME".
|
||||
void
|
||||
note_usage() const
|
||||
{ this->used_++; }
|
||||
note_usage(const std::string& alias) const;
|
||||
|
||||
// Note that USAGE might be a fake usage of this package.
|
||||
void
|
||||
@ -2852,36 +2886,6 @@ class Package
|
||||
void
|
||||
clear_used();
|
||||
|
||||
// Whether this package was imported in the current file.
|
||||
bool
|
||||
is_imported() const
|
||||
{ return this->is_imported_; }
|
||||
|
||||
// Note that this package was imported in the current file.
|
||||
void
|
||||
set_is_imported()
|
||||
{ this->is_imported_ = true; }
|
||||
|
||||
// Clear the imported field for the next file.
|
||||
void
|
||||
clear_is_imported()
|
||||
{ this->is_imported_ = false; }
|
||||
|
||||
// Whether this package was imported with a name of "_".
|
||||
bool
|
||||
uses_sink_alias() const
|
||||
{ return this->uses_sink_alias_; }
|
||||
|
||||
// Note that this package was imported with a name of "_".
|
||||
void
|
||||
set_uses_sink_alias()
|
||||
{ this->uses_sink_alias_ = true; }
|
||||
|
||||
// Clear the sink alias field for the next file.
|
||||
void
|
||||
clear_uses_sink_alias()
|
||||
{ this->uses_sink_alias_ = false; }
|
||||
|
||||
// Look up a name in the package. Returns NULL if the name is not
|
||||
// found.
|
||||
Named_object*
|
||||
@ -2898,6 +2902,10 @@ class Package
|
||||
set_location(Location location)
|
||||
{ this->location_ = location; }
|
||||
|
||||
// Add a package name as an ALIAS for this package.
|
||||
Package_alias*
|
||||
add_alias(const std::string& alias, Location);
|
||||
|
||||
// Add a constant to the package.
|
||||
Named_object*
|
||||
add_constant(const Typed_identifier& tid, Expression* expr)
|
||||
@ -2942,18 +2950,13 @@ class Package
|
||||
// than the priority of all of the packages that it imports. This
|
||||
// is used to run init functions in the right order.
|
||||
int priority_;
|
||||
// The location of the import statement.
|
||||
// The location of the most recent import statement.
|
||||
Location location_;
|
||||
// The amount of times some name from this package was used. This is mutable
|
||||
// because we can use a package even if we have a const pointer to it.
|
||||
mutable size_t used_;
|
||||
// A set of possibly fake uses of this package. This is mutable because we
|
||||
// The set of aliases associated with this package.
|
||||
Aliases aliases_;
|
||||
// A set of possibly fake uses of this package. This is mutable because we
|
||||
// can track fake uses of a package even if we have a const pointer to it.
|
||||
mutable std::set<Expression*> fake_uses_;
|
||||
// True if this package was imported in the current file.
|
||||
bool is_imported_;
|
||||
// True if this package was imported with a name of "_".
|
||||
bool uses_sink_alias_;
|
||||
};
|
||||
|
||||
// Return codes for the traversal functions. This is not an enum
|
||||
|
@ -198,7 +198,7 @@ Parse::qualified_ident(std::string* pname, Named_object** ppackage)
|
||||
return false;
|
||||
}
|
||||
|
||||
package->package_value()->note_usage();
|
||||
package->package_value()->note_usage(Gogo::unpack_hidden_name(name));
|
||||
|
||||
token = this->advance_token();
|
||||
if (!token->is_identifier())
|
||||
@ -2430,7 +2430,7 @@ Parse::operand(bool may_be_sink, bool* is_parenthesized)
|
||||
return Expression::make_error(location);
|
||||
}
|
||||
package = named_object->package_value();
|
||||
package->note_usage();
|
||||
package->note_usage(id);
|
||||
id = this->peek_token()->identifier();
|
||||
is_exported = this->peek_token()->is_identifier_exported();
|
||||
packed = this->gogo_->pack_hidden_name(id, is_exported);
|
||||
|
@ -32,8 +32,6 @@ Gogo::import_unsafe(const std::string& local_name, bool is_local_name_exported,
|
||||
}
|
||||
|
||||
package->set_location(location);
|
||||
package->set_is_imported();
|
||||
|
||||
this->imports_.insert(std::make_pair("unsafe", package));
|
||||
|
||||
Bindings* bindings = package->bindings();
|
||||
|
@ -2,7 +2,7 @@ package p
|
||||
|
||||
import (
|
||||
"./a" // ERROR "imported and not used: \x22a\x22 as surprise|imported and not used: surprise"
|
||||
"./b" // GC_ERROR "imported and not used: \x22b\x22 as surprise2|imported and not used: surprise2"
|
||||
"./b" // ERROR "imported and not used: \x22b\x22 as surprise2|imported and not used: surprise2"
|
||||
b "./b" // ERROR "imported and not used: \x22b\x22$|imported and not used: surprise2"
|
||||
foo "math" // ERROR "imported and not used: \x22math\x22 as foo|imported and not used: math"
|
||||
"fmt" // actually used
|
||||
|
@ -18,7 +18,7 @@ import X "math" // ERROR "imported and not used.*math"
|
||||
import . "bufio" // ERROR "imported and not used.*bufio"
|
||||
|
||||
// again, package without anything in it
|
||||
import "./empty" // GC_ERROR "imported and not used.*empty"
|
||||
import Z "./empty" // GC_ERROR "imported and not used.*empty"
|
||||
import "./empty" // ERROR "imported and not used.*empty"
|
||||
import Z "./empty" // ERROR "imported and not used.*empty"
|
||||
import . "./empty" // ERROR "imported and not used.*empty"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user