forked from OSchip/llvm-project
[include-fixer] Add usage count to find-all-symbols.
Summary: Add usage count to find-all-symbols. FindAllSymbols now finds (most!) main-file usages of the discovered symbols. The per-TU map output has NumUses=0 or 1 (only one use per file is counted). The reducer aggregates these to find the number of files that use a symbol. The NumOccurrences is now set to 1 in the mapper rather than being inferred by the reducer, for consistency. The idea here is to use NumUses for ranking: intuitively number of files that use a symbol is more meaningful than number of files that include the header. Reviewers: hokein, bkramer Subscribers: cfe-commits Differential Revision: https://reviews.llvm.org/D30210 llvm-svn: 296446
This commit is contained in:
parent
427215ce5e
commit
b27dc2245f
|
@ -9,18 +9,18 @@
|
|||
|
||||
#include "InMemorySymbolIndex.h"
|
||||
|
||||
using clang::find_all_symbols::SymbolInfo;
|
||||
using clang::find_all_symbols::SymbolAndSignals;
|
||||
|
||||
namespace clang {
|
||||
namespace include_fixer {
|
||||
|
||||
InMemorySymbolIndex::InMemorySymbolIndex(
|
||||
const std::vector<SymbolInfo> &Symbols) {
|
||||
const std::vector<SymbolAndSignals> &Symbols) {
|
||||
for (const auto &Symbol : Symbols)
|
||||
LookupTable[Symbol.getName()].push_back(Symbol);
|
||||
LookupTable[Symbol.Symbol.getName()].push_back(Symbol);
|
||||
}
|
||||
|
||||
std::vector<SymbolInfo>
|
||||
std::vector<SymbolAndSignals>
|
||||
InMemorySymbolIndex::search(llvm::StringRef Identifier) {
|
||||
auto I = LookupTable.find(Identifier);
|
||||
if (I != LookupTable.end())
|
||||
|
|
|
@ -21,13 +21,14 @@ namespace include_fixer {
|
|||
/// Xref database with fixed content.
|
||||
class InMemorySymbolIndex : public SymbolIndex {
|
||||
public:
|
||||
InMemorySymbolIndex(const std::vector<find_all_symbols::SymbolInfo> &Symbols);
|
||||
InMemorySymbolIndex(
|
||||
const std::vector<find_all_symbols::SymbolAndSignals> &Symbols);
|
||||
|
||||
std::vector<clang::find_all_symbols::SymbolInfo>
|
||||
std::vector<find_all_symbols::SymbolAndSignals>
|
||||
search(llvm::StringRef Identifier) override;
|
||||
|
||||
private:
|
||||
std::map<std::string, std::vector<clang::find_all_symbols::SymbolInfo>>
|
||||
std::map<std::string, std::vector<find_all_symbols::SymbolAndSignals>>
|
||||
LookupTable;
|
||||
};
|
||||
|
||||
|
|
|
@ -334,8 +334,7 @@ IncludeFixerContext IncludeFixerSemaSource::getIncludeFixerContext(
|
|||
SourceManager, HeaderSearch);
|
||||
SymbolCandidates.emplace_back(Symbol.getName(), Symbol.getSymbolKind(),
|
||||
MinimizedFilePath, Symbol.getLineNumber(),
|
||||
Symbol.getContexts(),
|
||||
Symbol.getNumOccurrences());
|
||||
Symbol.getContexts());
|
||||
}
|
||||
return IncludeFixerContext(FilePath, QuerySymbolInfos, SymbolCandidates);
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ public:
|
|||
/// \returns A list of `SymbolInfo` candidates.
|
||||
// FIXME: Expose the type name so we can also insert using declarations (or
|
||||
// fix the usage)
|
||||
virtual std::vector<clang::find_all_symbols::SymbolInfo>
|
||||
virtual std::vector<find_all_symbols::SymbolAndSignals>
|
||||
search(llvm::StringRef Identifier) = 0;
|
||||
};
|
||||
|
||||
|
|
|
@ -19,7 +19,8 @@
|
|||
namespace clang {
|
||||
namespace include_fixer {
|
||||
|
||||
using clang::find_all_symbols::SymbolInfo;
|
||||
using find_all_symbols::SymbolInfo;
|
||||
using find_all_symbols::SymbolAndSignals;
|
||||
|
||||
// Calculate a score based on whether we think the given header is closely
|
||||
// related to the given source file.
|
||||
|
@ -45,26 +46,26 @@ static double similarityScore(llvm::StringRef FileName,
|
|||
return MaxSegments;
|
||||
}
|
||||
|
||||
static void rank(std::vector<SymbolInfo> &Symbols,
|
||||
static void rank(std::vector<SymbolAndSignals> &Symbols,
|
||||
llvm::StringRef FileName) {
|
||||
llvm::DenseMap<llvm::StringRef, double> Score;
|
||||
for (const SymbolInfo &Symbol : Symbols) {
|
||||
for (const auto &Symbol : Symbols) {
|
||||
// Calculate a score from the similarity of the header the symbol is in
|
||||
// with the current file and the popularity of the symbol.
|
||||
double NewScore = similarityScore(FileName, Symbol.getFilePath()) *
|
||||
(1.0 + std::log2(1 + Symbol.getNumOccurrences()));
|
||||
double &S = Score[Symbol.getFilePath()];
|
||||
double NewScore = similarityScore(FileName, Symbol.Symbol.getFilePath()) *
|
||||
(1.0 + std::log2(1 + Symbol.Signals.Seen));
|
||||
double &S = Score[Symbol.Symbol.getFilePath()];
|
||||
S = std::max(S, NewScore);
|
||||
}
|
||||
// Sort by the gathered scores. Use file name as a tie breaker so we can
|
||||
// deduplicate.
|
||||
std::sort(Symbols.begin(), Symbols.end(),
|
||||
[&](const SymbolInfo &A, const SymbolInfo &B) {
|
||||
auto AS = Score[A.getFilePath()];
|
||||
auto BS = Score[B.getFilePath()];
|
||||
[&](const SymbolAndSignals &A, const SymbolAndSignals &B) {
|
||||
auto AS = Score[A.Symbol.getFilePath()];
|
||||
auto BS = Score[B.Symbol.getFilePath()];
|
||||
if (AS != BS)
|
||||
return AS > BS;
|
||||
return A.getFilePath() < B.getFilePath();
|
||||
return A.Symbol.getFilePath() < B.Symbol.getFilePath();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -88,9 +89,9 @@ SymbolIndexManager::search(llvm::StringRef Identifier,
|
|||
// Eventually we will either hit a class (namespaces aren't in the database
|
||||
// either) and can report that result.
|
||||
bool TookPrefix = false;
|
||||
std::vector<clang::find_all_symbols::SymbolInfo> MatchedSymbols;
|
||||
std::vector<SymbolAndSignals> MatchedSymbols;
|
||||
do {
|
||||
std::vector<clang::find_all_symbols::SymbolInfo> Symbols;
|
||||
std::vector<SymbolAndSignals> Symbols;
|
||||
for (const auto &DB : SymbolIndices) {
|
||||
auto Res = DB.get()->search(Names.back());
|
||||
Symbols.insert(Symbols.end(), Res.begin(), Res.end());
|
||||
|
@ -99,7 +100,8 @@ SymbolIndexManager::search(llvm::StringRef Identifier,
|
|||
DEBUG(llvm::dbgs() << "Searching " << Names.back() << "... got "
|
||||
<< Symbols.size() << " results...\n");
|
||||
|
||||
for (const auto &Symbol : Symbols) {
|
||||
for (auto &SymAndSig : Symbols) {
|
||||
const SymbolInfo &Symbol = SymAndSig.Symbol;
|
||||
// Match the identifier name without qualifier.
|
||||
if (Symbol.getName() == Names.back()) {
|
||||
bool IsMatched = true;
|
||||
|
@ -139,7 +141,7 @@ SymbolIndexManager::search(llvm::StringRef Identifier,
|
|||
Symbol.getSymbolKind() == SymbolInfo::SymbolKind::Macro))
|
||||
continue;
|
||||
|
||||
MatchedSymbols.push_back(Symbol);
|
||||
MatchedSymbols.push_back(std::move(SymAndSig));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -148,7 +150,11 @@ SymbolIndexManager::search(llvm::StringRef Identifier,
|
|||
} while (MatchedSymbols.empty() && !Names.empty() && IsNestedSearch);
|
||||
|
||||
rank(MatchedSymbols, FileName);
|
||||
return MatchedSymbols;
|
||||
// Strip signals, they are no longer needed.
|
||||
std::vector<SymbolInfo> Res;
|
||||
for (const auto &SymAndSig : MatchedSymbols)
|
||||
Res.push_back(std::move(SymAndSig.Symbol));
|
||||
return Res;
|
||||
}
|
||||
|
||||
} // namespace include_fixer
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <vector>
|
||||
|
||||
using clang::find_all_symbols::SymbolInfo;
|
||||
using clang::find_all_symbols::SymbolAndSignals;
|
||||
|
||||
namespace clang {
|
||||
namespace include_fixer {
|
||||
|
@ -27,9 +28,8 @@ YamlSymbolIndex::createFromFile(llvm::StringRef FilePath) {
|
|||
if (!Buffer)
|
||||
return Buffer.getError();
|
||||
|
||||
return std::unique_ptr<YamlSymbolIndex>(
|
||||
new YamlSymbolIndex(clang::find_all_symbols::ReadSymbolInfosFromYAML(
|
||||
Buffer.get()->getBuffer())));
|
||||
return std::unique_ptr<YamlSymbolIndex>(new YamlSymbolIndex(
|
||||
find_all_symbols::ReadSymbolInfosFromYAML(Buffer.get()->getBuffer())));
|
||||
}
|
||||
|
||||
llvm::ErrorOr<std::unique_ptr<YamlSymbolIndex>>
|
||||
|
@ -47,10 +47,11 @@ YamlSymbolIndex::createFromDirectory(llvm::StringRef Directory,
|
|||
return llvm::make_error_code(llvm::errc::no_such_file_or_directory);
|
||||
}
|
||||
|
||||
std::vector<SymbolInfo> YamlSymbolIndex::search(llvm::StringRef Identifier) {
|
||||
std::vector<SymbolInfo> Results;
|
||||
std::vector<SymbolAndSignals>
|
||||
YamlSymbolIndex::search(llvm::StringRef Identifier) {
|
||||
std::vector<SymbolAndSignals> Results;
|
||||
for (const auto &Symbol : Symbols) {
|
||||
if (Symbol.getName() == Identifier)
|
||||
if (Symbol.Symbol.getName() == Identifier)
|
||||
Results.push_back(Symbol);
|
||||
}
|
||||
return Results;
|
||||
|
|
|
@ -29,15 +29,15 @@ public:
|
|||
static llvm::ErrorOr<std::unique_ptr<YamlSymbolIndex>>
|
||||
createFromDirectory(llvm::StringRef Directory, llvm::StringRef Name);
|
||||
|
||||
std::vector<clang::find_all_symbols::SymbolInfo>
|
||||
std::vector<find_all_symbols::SymbolAndSignals>
|
||||
search(llvm::StringRef Identifier) override;
|
||||
|
||||
private:
|
||||
explicit YamlSymbolIndex(
|
||||
std::vector<clang::find_all_symbols::SymbolInfo> Symbols)
|
||||
std::vector<find_all_symbols::SymbolAndSignals> Symbols)
|
||||
: Symbols(std::move(Symbols)) {}
|
||||
|
||||
std::vector<clang::find_all_symbols::SymbolInfo> Symbols;
|
||||
std::vector<find_all_symbols::SymbolAndSignals> Symbols;
|
||||
};
|
||||
|
||||
} // namespace include_fixer
|
||||
|
|
|
@ -13,24 +13,58 @@
|
|||
#include "SymbolInfo.h"
|
||||
#include "clang/Basic/IdentifierTable.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "clang/Lex/MacroInfo.h"
|
||||
#include "clang/Lex/Token.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
|
||||
namespace clang {
|
||||
namespace find_all_symbols {
|
||||
|
||||
llvm::Optional<SymbolInfo>
|
||||
FindAllMacros::CreateMacroSymbol(const Token &MacroNameTok,
|
||||
const MacroInfo *info) {
|
||||
std::string FilePath =
|
||||
getIncludePath(*SM, info->getDefinitionLoc(), Collector);
|
||||
if (FilePath.empty())
|
||||
return llvm::None;
|
||||
return SymbolInfo(MacroNameTok.getIdentifierInfo()->getName(),
|
||||
SymbolInfo::SymbolKind::Macro, FilePath,
|
||||
SM->getSpellingLineNumber(info->getDefinitionLoc()), {});
|
||||
}
|
||||
|
||||
void FindAllMacros::MacroDefined(const Token &MacroNameTok,
|
||||
const MacroDirective *MD) {
|
||||
SourceLocation Loc = SM->getExpansionLoc(MacroNameTok.getLocation());
|
||||
std::string FilePath = getIncludePath(*SM, Loc, Collector);
|
||||
if (FilePath.empty()) return;
|
||||
if (auto Symbol = CreateMacroSymbol(MacroNameTok, MD->getMacroInfo()))
|
||||
++FileSymbols[*Symbol].Seen;
|
||||
}
|
||||
|
||||
SymbolInfo Symbol(MacroNameTok.getIdentifierInfo()->getName(),
|
||||
SymbolInfo::SymbolKind::Macro, FilePath,
|
||||
SM->getSpellingLineNumber(Loc), {});
|
||||
void FindAllMacros::MacroUsed(const Token &Name, const MacroDefinition &MD) {
|
||||
if (!MD || !SM->isInMainFile(SM->getExpansionLoc(Name.getLocation())))
|
||||
return;
|
||||
if (auto Symbol = CreateMacroSymbol(Name, MD.getMacroInfo()))
|
||||
++FileSymbols[*Symbol].Used;
|
||||
}
|
||||
|
||||
Reporter->reportSymbol(SM->getFileEntryForID(SM->getMainFileID())->getName(),
|
||||
Symbol);
|
||||
void FindAllMacros::MacroExpands(const Token &MacroNameTok,
|
||||
const MacroDefinition &MD, SourceRange Range,
|
||||
const MacroArgs *Args) {
|
||||
MacroUsed(MacroNameTok, MD);
|
||||
}
|
||||
|
||||
void FindAllMacros::Ifdef(SourceLocation Loc, const Token &MacroNameTok,
|
||||
const MacroDefinition &MD) {
|
||||
MacroUsed(MacroNameTok, MD);
|
||||
}
|
||||
|
||||
void FindAllMacros::Ifndef(SourceLocation Loc, const Token &MacroNameTok,
|
||||
const MacroDefinition &MD) {
|
||||
MacroUsed(MacroNameTok, MD);
|
||||
}
|
||||
|
||||
void FindAllMacros::EndOfMainFile() {
|
||||
Reporter->reportSymbols(SM->getFileEntryForID(SM->getMainFileID())->getName(),
|
||||
FileSymbols);
|
||||
FileSymbols.clear();
|
||||
}
|
||||
|
||||
} // namespace find_all_symbols
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "clang/Lex/PPCallbacks.h"
|
||||
|
||||
namespace clang {
|
||||
class MacroInfo;
|
||||
namespace find_all_symbols {
|
||||
|
||||
class HeaderMapCollector;
|
||||
|
@ -32,7 +33,24 @@ public:
|
|||
void MacroDefined(const Token &MacroNameTok,
|
||||
const MacroDirective *MD) override;
|
||||
|
||||
void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD,
|
||||
SourceRange Range, const MacroArgs *Args) override;
|
||||
|
||||
void Ifdef(SourceLocation Loc, const Token &MacroNameTok,
|
||||
const MacroDefinition &MD) override;
|
||||
|
||||
void Ifndef(SourceLocation Loc, const Token &MacroNameTok,
|
||||
const MacroDefinition &MD) override;
|
||||
|
||||
void EndOfMainFile() override;
|
||||
|
||||
private:
|
||||
llvm::Optional<SymbolInfo> CreateMacroSymbol(const Token &MacroNameTok,
|
||||
const MacroInfo *MD);
|
||||
// Not a callback, just a common path for all usage types.
|
||||
void MacroUsed(const Token &Name, const MacroDefinition &MD);
|
||||
|
||||
SymbolInfo::SignalMap FileSymbols;
|
||||
// Reporter for SymbolInfo.
|
||||
SymbolReporter *const Reporter;
|
||||
SourceManager *const SM;
|
||||
|
|
|
@ -154,64 +154,84 @@ void FindAllSymbols::registerMatchers(MatchFinder *MatchFinder) {
|
|||
// The float parameter of the function pointer has an empty name, and its
|
||||
// declaration context is an anonymous namespace; therefore, it won't be
|
||||
// filtered out by our matchers above.
|
||||
MatchFinder->addMatcher(varDecl(CommonFilter,
|
||||
anyOf(ExternCMatcher, CCMatcher),
|
||||
unless(parmVarDecl()))
|
||||
.bind("decl"),
|
||||
this);
|
||||
auto Vars = varDecl(CommonFilter, anyOf(ExternCMatcher, CCMatcher),
|
||||
unless(parmVarDecl()));
|
||||
|
||||
// Matchers for C-style record declarations in extern "C" {...}.
|
||||
MatchFinder->addMatcher(
|
||||
recordDecl(CommonFilter, ExternCMatcher, isDefinition()).bind("decl"),
|
||||
this);
|
||||
|
||||
auto CRecords = recordDecl(CommonFilter, ExternCMatcher, isDefinition());
|
||||
// Matchers for C++ record declarations.
|
||||
auto CxxRecordDecl =
|
||||
cxxRecordDecl(CommonFilter, CCMatcher, isDefinition());
|
||||
MatchFinder->addMatcher(CxxRecordDecl.bind("decl"), this);
|
||||
auto CXXRecords = cxxRecordDecl(CommonFilter, CCMatcher, isDefinition());
|
||||
|
||||
// Matchers for function declarations.
|
||||
// We want to exclude friend declaration, but the `DeclContext` of a friend
|
||||
// function declaration is not the class in which it is declared, so we need
|
||||
// to explicitly check if the parent is a `friendDecl`.
|
||||
MatchFinder->addMatcher(functionDecl(CommonFilter,
|
||||
unless(hasParent(friendDecl())),
|
||||
anyOf(ExternCMatcher, CCMatcher))
|
||||
.bind("decl"),
|
||||
this);
|
||||
auto Functions = functionDecl(CommonFilter, unless(hasParent(friendDecl())),
|
||||
anyOf(ExternCMatcher, CCMatcher));
|
||||
|
||||
// Matcher for typedef and type alias declarations.
|
||||
//
|
||||
// typedef and type alias can come from C-style headers and C++ heaeders.
|
||||
// For C-style header, `DeclContxet` can be either `TranslationUnitDecl`
|
||||
// typedef and type alias can come from C-style headers and C++ headers.
|
||||
// For C-style headers, `DeclContxet` can be either `TranslationUnitDecl`
|
||||
// or `LinkageSpecDecl`.
|
||||
// For C++ header, `DeclContext ` can be one of `TranslationUnitDecl`,
|
||||
// `NamespaceDecl`.
|
||||
// For C++ headers, `DeclContext ` can be either `TranslationUnitDecl`
|
||||
// or `NamespaceDecl`.
|
||||
// With the following context matcher, we can match `typedefNameDecl` from
|
||||
// both C-style header and C++ header (except for those in classes).
|
||||
// both C-style headers and C++ headers (except for those in classes).
|
||||
// "cc_matchers" are not included since template-related matchers are not
|
||||
// applicable on `TypedefNameDecl`.
|
||||
MatchFinder->addMatcher(
|
||||
auto Typedefs =
|
||||
typedefNameDecl(CommonFilter, anyOf(HasNSOrTUCtxMatcher,
|
||||
hasDeclContext(linkageSpecDecl())))
|
||||
.bind("decl"),
|
||||
this);
|
||||
hasDeclContext(linkageSpecDecl())));
|
||||
|
||||
// Matchers for enum declarations.
|
||||
MatchFinder->addMatcher(enumDecl(CommonFilter, isDefinition(),
|
||||
anyOf(HasNSOrTUCtxMatcher, ExternCMatcher))
|
||||
.bind("decl"),
|
||||
this);
|
||||
auto Enums = enumDecl(CommonFilter, isDefinition(),
|
||||
anyOf(HasNSOrTUCtxMatcher, ExternCMatcher));
|
||||
|
||||
// Matchers for enum constant declarations.
|
||||
// We only match the enum constants in non-scoped enum declarations which are
|
||||
// inside toplevel translation unit or a namespace.
|
||||
auto EnumConstants = enumConstantDecl(
|
||||
CommonFilter, unless(isInScopedEnum()),
|
||||
anyOf(hasDeclContext(enumDecl(HasNSOrTUCtxMatcher)), ExternCMatcher));
|
||||
|
||||
// Most of the time we care about all matchable decls, or all types.
|
||||
auto Types = namedDecl(anyOf(CRecords, CXXRecords, Enums, Typedefs));
|
||||
auto Decls = namedDecl(anyOf(CRecords, CXXRecords, Enums, Typedefs, Vars,
|
||||
EnumConstants, Functions));
|
||||
|
||||
// We want eligible decls bound to "decl"...
|
||||
MatchFinder->addMatcher(Decls.bind("decl"), this);
|
||||
|
||||
// ... and all uses of them bound to "use". These have many cases:
|
||||
// Uses of values/functions: these generate a declRefExpr.
|
||||
MatchFinder->addMatcher(
|
||||
enumConstantDecl(
|
||||
CommonFilter,
|
||||
unless(isInScopedEnum()),
|
||||
anyOf(hasDeclContext(enumDecl(HasNSOrTUCtxMatcher)), ExternCMatcher))
|
||||
.bind("decl"),
|
||||
declRefExpr(isExpansionInMainFile(), to(Decls.bind("use"))), this);
|
||||
// Uses of function templates:
|
||||
MatchFinder->addMatcher(
|
||||
declRefExpr(isExpansionInMainFile(),
|
||||
to(functionDecl(hasParent(
|
||||
functionTemplateDecl(has(Functions.bind("use"))))))),
|
||||
this);
|
||||
|
||||
// Uses of most types: just look at what the typeLoc refers to.
|
||||
MatchFinder->addMatcher(
|
||||
typeLoc(isExpansionInMainFile(),
|
||||
loc(qualType(hasDeclaration(Types.bind("use"))))),
|
||||
this);
|
||||
// Uses of typedefs: these are transparent to hasDeclaration, so we need to
|
||||
// handle them explicitly.
|
||||
MatchFinder->addMatcher(
|
||||
typeLoc(isExpansionInMainFile(),
|
||||
loc(typedefType(hasDeclaration(Typedefs.bind("use"))))),
|
||||
this);
|
||||
// Uses of class templates:
|
||||
// The typeLoc names the templateSpecializationType. Its declaration is the
|
||||
// ClassTemplateDecl, which contains the CXXRecordDecl we want.
|
||||
MatchFinder->addMatcher(
|
||||
typeLoc(isExpansionInMainFile(),
|
||||
loc(templateSpecializationType(hasDeclaration(
|
||||
classTemplateDecl(has(CXXRecords.bind("use"))))))),
|
||||
this);
|
||||
}
|
||||
|
||||
|
@ -221,15 +241,28 @@ void FindAllSymbols::run(const MatchFinder::MatchResult &Result) {
|
|||
return;
|
||||
}
|
||||
|
||||
const auto *ND = Result.Nodes.getNodeAs<NamedDecl>("decl");
|
||||
assert(ND && "Matched declaration must be a NamedDecl!");
|
||||
const SourceManager *SM = Result.SourceManager;
|
||||
SymbolInfo::Signals Signals;
|
||||
const NamedDecl *ND;
|
||||
if ((ND = Result.Nodes.getNodeAs<NamedDecl>("use")))
|
||||
Signals.Used = 1;
|
||||
else if ((ND = Result.Nodes.getNodeAs<NamedDecl>("decl")))
|
||||
Signals.Seen = 1;
|
||||
else
|
||||
assert(false && "Must match a NamedDecl!");
|
||||
|
||||
llvm::Optional<SymbolInfo> Symbol =
|
||||
CreateSymbolInfo(ND, *SM, Collector);
|
||||
if (Symbol)
|
||||
Reporter->reportSymbol(
|
||||
SM->getFileEntryForID(SM->getMainFileID())->getName(), *Symbol);
|
||||
const SourceManager *SM = Result.SourceManager;
|
||||
if (auto Symbol = CreateSymbolInfo(ND, *SM, Collector)) {
|
||||
Filename = SM->getFileEntryForID(SM->getMainFileID())->getName();
|
||||
FileSymbols[*Symbol] += Signals;
|
||||
}
|
||||
}
|
||||
|
||||
void FindAllSymbols::onEndOfTranslationUnit() {
|
||||
if (Filename != "") {
|
||||
Reporter->reportSymbols(Filename, FileSymbols);
|
||||
FileSymbols.clear();
|
||||
Filename = "";
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace find_all_symbols
|
||||
|
|
|
@ -32,18 +32,24 @@ class HeaderMapCollector;
|
|||
/// through the class. #include fixer only needs the class name to find
|
||||
/// headers.
|
||||
///
|
||||
class FindAllSymbols : public clang::ast_matchers::MatchFinder::MatchCallback {
|
||||
class FindAllSymbols : public ast_matchers::MatchFinder::MatchCallback {
|
||||
public:
|
||||
explicit FindAllSymbols(SymbolReporter *Reporter,
|
||||
HeaderMapCollector *Collector = nullptr)
|
||||
: Reporter(Reporter), Collector(Collector) {}
|
||||
|
||||
void registerMatchers(clang::ast_matchers::MatchFinder *MatchFinder);
|
||||
void registerMatchers(ast_matchers::MatchFinder *MatchFinder);
|
||||
|
||||
void
|
||||
run(const clang::ast_matchers::MatchFinder::MatchResult &result) override;
|
||||
void run(const ast_matchers::MatchFinder::MatchResult &result) override;
|
||||
|
||||
protected:
|
||||
void onEndOfTranslationUnit() override;
|
||||
|
||||
private:
|
||||
// Current source file being processed, filled by first symbol found.
|
||||
std::string Filename;
|
||||
// Findings for the current source file, flushed on onEndOfTranslationUnit.
|
||||
SymbolInfo::SignalMap FileSymbols;
|
||||
// Reporter for SymbolInfo.
|
||||
SymbolReporter *const Reporter;
|
||||
// A remapping header file collector allowing clients include a different
|
||||
|
|
|
@ -24,8 +24,8 @@ FindAllSymbolsAction::FindAllSymbolsAction(
|
|||
Matcher.registerMatchers(&MatchFinder);
|
||||
}
|
||||
|
||||
std::unique_ptr<clang::ASTConsumer>
|
||||
FindAllSymbolsAction::CreateASTConsumer(clang::CompilerInstance &Compiler,
|
||||
std::unique_ptr<ASTConsumer>
|
||||
FindAllSymbolsAction::CreateASTConsumer(CompilerInstance &Compiler,
|
||||
StringRef InFile) {
|
||||
Compiler.getPreprocessor().addCommentHandler(&Handler);
|
||||
Compiler.getPreprocessor().addPPCallbacks(llvm::make_unique<FindAllMacros>(
|
||||
|
|
|
@ -18,22 +18,24 @@ using llvm::yaml::IO;
|
|||
using llvm::yaml::Input;
|
||||
using ContextType = clang::find_all_symbols::SymbolInfo::ContextType;
|
||||
using clang::find_all_symbols::SymbolInfo;
|
||||
using clang::find_all_symbols::SymbolAndSignals;
|
||||
using SymbolKind = clang::find_all_symbols::SymbolInfo::SymbolKind;
|
||||
|
||||
LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(SymbolInfo)
|
||||
LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(SymbolAndSignals)
|
||||
LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(std::string)
|
||||
LLVM_YAML_IS_SEQUENCE_VECTOR(SymbolInfo::Context)
|
||||
|
||||
namespace llvm {
|
||||
namespace yaml {
|
||||
template <> struct MappingTraits<SymbolInfo> {
|
||||
static void mapping(IO &io, SymbolInfo &Symbol) {
|
||||
io.mapRequired("Name", Symbol.Name);
|
||||
io.mapRequired("Contexts", Symbol.Contexts);
|
||||
io.mapRequired("FilePath", Symbol.FilePath);
|
||||
io.mapRequired("LineNumber", Symbol.LineNumber);
|
||||
io.mapRequired("Type", Symbol.Type);
|
||||
io.mapRequired("NumOccurrences", Symbol.NumOccurrences);
|
||||
template <> struct MappingTraits<SymbolAndSignals> {
|
||||
static void mapping(IO &io, SymbolAndSignals &Symbol) {
|
||||
io.mapRequired("Name", Symbol.Symbol.Name);
|
||||
io.mapRequired("Contexts", Symbol.Symbol.Contexts);
|
||||
io.mapRequired("FilePath", Symbol.Symbol.FilePath);
|
||||
io.mapRequired("LineNumber", Symbol.Symbol.LineNumber);
|
||||
io.mapRequired("Type", Symbol.Symbol.Type);
|
||||
io.mapRequired("Seen", Symbol.Signals.Seen);
|
||||
io.mapRequired("Used", Symbol.Signals.Used);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -73,10 +75,9 @@ namespace find_all_symbols {
|
|||
|
||||
SymbolInfo::SymbolInfo(llvm::StringRef Name, SymbolKind Type,
|
||||
llvm::StringRef FilePath, int LineNumber,
|
||||
const std::vector<Context> &Contexts,
|
||||
unsigned NumOccurrences)
|
||||
const std::vector<Context> &Contexts)
|
||||
: Name(Name), Type(Type), FilePath(FilePath), Contexts(Contexts),
|
||||
LineNumber(LineNumber), NumOccurrences(NumOccurrences) {}
|
||||
LineNumber(LineNumber) {}
|
||||
|
||||
bool SymbolInfo::operator==(const SymbolInfo &Symbol) const {
|
||||
return std::tie(Name, Type, FilePath, LineNumber, Contexts) ==
|
||||
|
@ -100,16 +101,30 @@ std::string SymbolInfo::getQualifiedName() const {
|
|||
return QualifiedName;
|
||||
}
|
||||
|
||||
SymbolInfo::Signals &SymbolInfo::Signals::operator+=(const Signals &RHS) {
|
||||
Seen += RHS.Seen;
|
||||
Used += RHS.Used;
|
||||
return *this;
|
||||
}
|
||||
|
||||
SymbolInfo::Signals SymbolInfo::Signals::operator+(const Signals &RHS) const {
|
||||
Signals Result = *this;
|
||||
Result += RHS;
|
||||
return Result;
|
||||
}
|
||||
|
||||
bool WriteSymbolInfosToStream(llvm::raw_ostream &OS,
|
||||
const std::set<SymbolInfo> &Symbols) {
|
||||
const SymbolInfo::SignalMap &Symbols) {
|
||||
llvm::yaml::Output yout(OS);
|
||||
for (auto Symbol : Symbols)
|
||||
yout << Symbol;
|
||||
for (const auto &Symbol : Symbols) {
|
||||
SymbolAndSignals S{Symbol.first, Symbol.second};
|
||||
yout << S;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<SymbolInfo> ReadSymbolInfosFromYAML(llvm::StringRef Yaml) {
|
||||
std::vector<SymbolInfo> Symbols;
|
||||
std::vector<SymbolAndSignals> ReadSymbolInfosFromYAML(llvm::StringRef Yaml) {
|
||||
std::vector<SymbolAndSignals> Symbols;
|
||||
llvm::yaml::Input yin(Yaml);
|
||||
yin >> Symbols;
|
||||
return Symbols;
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
|
||||
namespace clang {
|
||||
namespace find_all_symbols {
|
||||
|
||||
/// \brief Contains all information for a Symbol.
|
||||
class SymbolInfo {
|
||||
public:
|
||||
|
@ -46,13 +45,30 @@ public:
|
|||
/// \brief A pair of <ContextType, ContextName>.
|
||||
typedef std::pair<ContextType, std::string> Context;
|
||||
|
||||
// \brief Signals are signals gathered by observing how a symbol is used.
|
||||
// These are used to rank results.
|
||||
struct Signals {
|
||||
Signals() {}
|
||||
Signals(unsigned Seen, unsigned Used) : Seen(Seen), Used(Used) {}
|
||||
|
||||
// Number of times this symbol was visible to a TU.
|
||||
unsigned Seen = 0;
|
||||
|
||||
// Number of times this symbol was referenced a TU's main file.
|
||||
unsigned Used = 0;
|
||||
|
||||
Signals &operator+=(const Signals &RHS);
|
||||
Signals operator+(const Signals &RHS) const;
|
||||
};
|
||||
|
||||
using SignalMap = std::map<SymbolInfo, Signals>;
|
||||
|
||||
// The default constructor is required by YAML traits in
|
||||
// LLVM_YAML_IS_DOCUMENT_LIST_VECTOR.
|
||||
SymbolInfo() : Type(SymbolKind::Unknown), LineNumber(-1) {}
|
||||
|
||||
SymbolInfo(llvm::StringRef Name, SymbolKind Type, llvm::StringRef FilePath,
|
||||
int LineNumber, const std::vector<Context> &Contexts,
|
||||
unsigned NumOccurrences = 0);
|
||||
int LineNumber, const std::vector<Context> &Contexts);
|
||||
|
||||
void SetFilePath(llvm::StringRef Path) { FilePath = Path; }
|
||||
|
||||
|
@ -76,15 +92,12 @@ public:
|
|||
/// \brief Get a 1-based line number of the symbol's declaration.
|
||||
int getLineNumber() const { return LineNumber; }
|
||||
|
||||
/// \brief The number of times this symbol was found during an indexing run.
|
||||
unsigned getNumOccurrences() const { return NumOccurrences; }
|
||||
|
||||
bool operator<(const SymbolInfo &Symbol) const;
|
||||
|
||||
bool operator==(const SymbolInfo &Symbol) const;
|
||||
|
||||
private:
|
||||
friend struct llvm::yaml::MappingTraits<SymbolInfo>;
|
||||
friend struct llvm::yaml::MappingTraits<struct SymbolAndSignals>;
|
||||
|
||||
/// \brief Identifier name.
|
||||
std::string Name;
|
||||
|
@ -110,18 +123,19 @@ private:
|
|||
|
||||
/// \brief The 1-based line number of of the symbol's declaration.
|
||||
int LineNumber;
|
||||
};
|
||||
|
||||
/// \brief The number of times this symbol was found during an indexing
|
||||
/// run. Populated by the reducer and used to rank results.
|
||||
unsigned NumOccurrences;
|
||||
struct SymbolAndSignals {
|
||||
SymbolInfo Symbol;
|
||||
SymbolInfo::Signals Signals;
|
||||
};
|
||||
|
||||
/// \brief Write SymbolInfos to a stream (YAML format).
|
||||
bool WriteSymbolInfosToStream(llvm::raw_ostream &OS,
|
||||
const std::set<SymbolInfo> &Symbols);
|
||||
const SymbolInfo::SignalMap &Symbols);
|
||||
|
||||
/// \brief Read SymbolInfos from a YAML document.
|
||||
std::vector<SymbolInfo> ReadSymbolInfosFromYAML(llvm::StringRef Yaml);
|
||||
std::vector<SymbolAndSignals> ReadSymbolInfosFromYAML(llvm::StringRef Yaml);
|
||||
|
||||
} // namespace find_all_symbols
|
||||
} // namespace clang
|
||||
|
|
|
@ -20,8 +20,8 @@ class SymbolReporter {
|
|||
public:
|
||||
virtual ~SymbolReporter() = default;
|
||||
|
||||
virtual void reportSymbol(llvm::StringRef FileName,
|
||||
const SymbolInfo &Symbol) = 0;
|
||||
virtual void reportSymbols(llvm::StringRef FileName,
|
||||
const SymbolInfo::SignalMap &Symbols) = 0;
|
||||
};
|
||||
|
||||
} // namespace find_all_symbols
|
||||
|
|
|
@ -62,38 +62,30 @@ The directory for merging symbols.)"),
|
|||
namespace clang {
|
||||
namespace find_all_symbols {
|
||||
|
||||
class YamlReporter : public clang::find_all_symbols::SymbolReporter {
|
||||
class YamlReporter : public SymbolReporter {
|
||||
public:
|
||||
~YamlReporter() override {
|
||||
for (const auto &Symbol : Symbols) {
|
||||
int FD;
|
||||
SmallString<128> ResultPath;
|
||||
llvm::sys::fs::createUniqueFile(
|
||||
OutputDir + "/" + llvm::sys::path::filename(Symbol.first) +
|
||||
"-%%%%%%.yaml",
|
||||
FD, ResultPath);
|
||||
llvm::raw_fd_ostream OS(FD, /*shouldClose=*/true);
|
||||
WriteSymbolInfosToStream(OS, Symbol.second);
|
||||
}
|
||||
void reportSymbols(StringRef FileName,
|
||||
const SymbolInfo::SignalMap &Symbols) override {
|
||||
int FD;
|
||||
SmallString<128> ResultPath;
|
||||
llvm::sys::fs::createUniqueFile(
|
||||
OutputDir + "/" + llvm::sys::path::filename(FileName) + "-%%%%%%.yaml",
|
||||
FD, ResultPath);
|
||||
llvm::raw_fd_ostream OS(FD, /*shouldClose=*/true);
|
||||
WriteSymbolInfosToStream(OS, Symbols);
|
||||
}
|
||||
|
||||
void reportSymbol(StringRef FileName, const SymbolInfo &Symbol) override {
|
||||
Symbols[FileName].insert(Symbol);
|
||||
}
|
||||
|
||||
private:
|
||||
std::map<std::string, std::set<SymbolInfo>> Symbols;
|
||||
};
|
||||
|
||||
bool Merge(llvm::StringRef MergeDir, llvm::StringRef OutputFile) {
|
||||
std::error_code EC;
|
||||
std::map<SymbolInfo, int> SymbolToNumOccurrences;
|
||||
SymbolInfo::SignalMap Symbols;
|
||||
std::mutex SymbolMutex;
|
||||
auto AddSymbols = [&](ArrayRef<SymbolInfo> Symbols) {
|
||||
auto AddSymbols = [&](ArrayRef<SymbolAndSignals> NewSymbols) {
|
||||
// Synchronize set accesses.
|
||||
std::unique_lock<std::mutex> LockGuard(SymbolMutex);
|
||||
for (const auto &Symbol : Symbols)
|
||||
++SymbolToNumOccurrences[Symbol];
|
||||
for (const auto &Symbol : NewSymbols) {
|
||||
Symbols[Symbol.Symbol] += Symbol.Signals;
|
||||
}
|
||||
};
|
||||
|
||||
// Load all symbol files in MergeDir.
|
||||
|
@ -109,8 +101,13 @@ bool Merge(llvm::StringRef MergeDir, llvm::StringRef OutputFile) {
|
|||
llvm::errs() << "Can't open " << Path << "\n";
|
||||
return;
|
||||
}
|
||||
std::vector<SymbolInfo> Symbols =
|
||||
std::vector<SymbolAndSignals> Symbols =
|
||||
ReadSymbolInfosFromYAML(Buffer.get()->getBuffer());
|
||||
for (auto &Symbol : Symbols) {
|
||||
// Only count one occurrence per file, to avoid spam.
|
||||
Symbol.Signals.Seen = std::min(Symbol.Signals.Seen, 1u);
|
||||
Symbol.Signals.Used = std::min(Symbol.Signals.Used, 1u);
|
||||
}
|
||||
// FIXME: Merge without creating such a heavy contention point.
|
||||
AddSymbols(Symbols);
|
||||
},
|
||||
|
@ -124,14 +121,7 @@ bool Merge(llvm::StringRef MergeDir, llvm::StringRef OutputFile) {
|
|||
<< '\n';
|
||||
return false;
|
||||
}
|
||||
std::set<SymbolInfo> Result;
|
||||
for (const auto &Entry : SymbolToNumOccurrences) {
|
||||
const auto &Symbol = Entry.first;
|
||||
Result.insert(SymbolInfo(Symbol.getName(), Symbol.getSymbolKind(),
|
||||
Symbol.getFilePath(), Symbol.getLineNumber(),
|
||||
Symbol.getContexts(), Entry.second));
|
||||
}
|
||||
WriteSymbolInfosToStream(OS, Result);
|
||||
WriteSymbolInfosToStream(OS, Symbols);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -158,6 +158,8 @@ cl::opt<std::string>
|
|||
|
||||
std::unique_ptr<include_fixer::SymbolIndexManager>
|
||||
createSymbolIndexManager(StringRef FilePath) {
|
||||
using find_all_symbols::SymbolInfo;
|
||||
|
||||
auto SymbolIndexMgr = llvm::make_unique<include_fixer::SymbolIndexManager>();
|
||||
switch (DatabaseFormat) {
|
||||
case fixed: {
|
||||
|
@ -167,17 +169,19 @@ createSymbolIndexManager(StringRef FilePath) {
|
|||
std::map<std::string, std::vector<std::string>> SymbolsMap;
|
||||
SmallVector<StringRef, 4> SemicolonSplits;
|
||||
StringRef(Input).split(SemicolonSplits, ";");
|
||||
std::vector<find_all_symbols::SymbolInfo> Symbols;
|
||||
std::vector<find_all_symbols::SymbolAndSignals> Symbols;
|
||||
for (StringRef Pair : SemicolonSplits) {
|
||||
auto Split = Pair.split('=');
|
||||
std::vector<std::string> Headers;
|
||||
SmallVector<StringRef, 4> CommaSplits;
|
||||
Split.second.split(CommaSplits, ",");
|
||||
for (size_t I = 0, E = CommaSplits.size(); I != E; ++I)
|
||||
Symbols.push_back(find_all_symbols::SymbolInfo(
|
||||
Split.first.trim(),
|
||||
find_all_symbols::SymbolInfo::SymbolKind::Unknown,
|
||||
CommaSplits[I].trim(), 1, {}, /*NumOccurrences=*/E - I));
|
||||
Symbols.push_back(
|
||||
{SymbolInfo(Split.first.trim(), SymbolInfo::SymbolKind::Unknown,
|
||||
CommaSplits[I].trim(), 1, {}),
|
||||
// Use fake "seen" signal for tests, so first header wins.
|
||||
SymbolInfo::Signals(/*Seen=*/static_cast<unsigned>(E - I),
|
||||
/*Used=*/0)});
|
||||
}
|
||||
SymbolIndexMgr->addSymbolIndex([=]() {
|
||||
return llvm::make_unique<include_fixer::InMemorySymbolIndex>(Symbols);
|
||||
|
|
|
@ -8,7 +8,8 @@ Contexts:
|
|||
FilePath: foo.h
|
||||
LineNumber: 1
|
||||
Type: Class
|
||||
NumOccurrences: 1
|
||||
Seen: 1
|
||||
Used: 0
|
||||
---
|
||||
Name: bar
|
||||
Contexts:
|
||||
|
@ -19,7 +20,8 @@ Contexts:
|
|||
FilePath: ../include/bar.h
|
||||
LineNumber: 1
|
||||
Type: Class
|
||||
NumOccurrences: 1
|
||||
Seen: 1
|
||||
Used: 0
|
||||
---
|
||||
Name: bar
|
||||
Contexts:
|
||||
|
@ -30,7 +32,8 @@ Contexts:
|
|||
FilePath: ../include/bar.h
|
||||
LineNumber: 2
|
||||
Type: Class
|
||||
NumOccurrences: 3
|
||||
Seen: 3
|
||||
Used: 0
|
||||
---
|
||||
Name: bar
|
||||
Contexts:
|
||||
|
@ -41,14 +44,16 @@ Contexts:
|
|||
FilePath: ../include/zbar.h
|
||||
LineNumber: 1
|
||||
Type: Class
|
||||
NumOccurrences: 3
|
||||
Seen: 3
|
||||
Used: 0
|
||||
---
|
||||
Name: b
|
||||
Contexts:
|
||||
FilePath: var.h
|
||||
LineNumber: 1
|
||||
Type: Variable
|
||||
NumOccurrences: 1
|
||||
Seen: 1
|
||||
Used: 0
|
||||
---
|
||||
Name: bar
|
||||
Contexts:
|
||||
|
@ -57,4 +62,5 @@ Contexts:
|
|||
FilePath: test/include-fixer/baz.h
|
||||
LineNumber: 1
|
||||
Type: Class
|
||||
NumOccurrences: 1
|
||||
Seen: 1
|
||||
Used: 0
|
||||
|
|
|
@ -6,7 +6,8 @@ Contexts:
|
|||
FilePath: foo.h
|
||||
LineNumber: 1
|
||||
Type: Class
|
||||
NumOccurrences: 1
|
||||
Seen: 1
|
||||
Used: 1
|
||||
...
|
||||
---
|
||||
Name: bar
|
||||
|
@ -16,5 +17,6 @@ Contexts:
|
|||
FilePath: ../include/bar.h
|
||||
LineNumber: 1
|
||||
Type: Class
|
||||
NumOccurrences: 1
|
||||
Seen: 1
|
||||
Used: 2
|
||||
...
|
||||
|
|
|
@ -6,7 +6,8 @@ Contexts:
|
|||
FilePath: foo.h
|
||||
LineNumber: 1
|
||||
Type: Class
|
||||
NumOccurrences: 1
|
||||
Seen: 1
|
||||
Used: 2
|
||||
...
|
||||
---
|
||||
Name: bar
|
||||
|
@ -16,5 +17,6 @@ Contexts:
|
|||
FilePath: ../include/barbar.h
|
||||
LineNumber: 1
|
||||
Type: Class
|
||||
NumOccurrences: 1
|
||||
Seen: 1
|
||||
Used: 0
|
||||
...
|
||||
|
|
|
@ -9,7 +9,8 @@ Contexts:
|
|||
FilePath: ../include/bar.h
|
||||
LineNumber: 1
|
||||
Type: Class
|
||||
NumOccurrences: 1
|
||||
Seen: 1
|
||||
Used: 1
|
||||
...
|
||||
---
|
||||
Name: bar
|
||||
|
@ -19,7 +20,8 @@ Contexts:
|
|||
FilePath: ../include/barbar.h
|
||||
LineNumber: 1
|
||||
Type: Class
|
||||
NumOccurrences: 1
|
||||
Seen: 1
|
||||
Used: 0
|
||||
...
|
||||
---
|
||||
Name: foo
|
||||
|
@ -29,5 +31,6 @@ Contexts:
|
|||
FilePath: foo.h
|
||||
LineNumber: 1
|
||||
Type: Class
|
||||
NumOccurrences: 2
|
||||
Seen: 2
|
||||
Used: 2
|
||||
...
|
||||
|
|
|
@ -19,6 +19,7 @@ namespace include_fixer {
|
|||
namespace {
|
||||
|
||||
using find_all_symbols::SymbolInfo;
|
||||
using find_all_symbols::SymbolAndSignals;
|
||||
|
||||
static bool runOnCode(tooling::ToolAction *ToolAction, StringRef Code,
|
||||
StringRef FileName,
|
||||
|
@ -52,42 +53,49 @@ static bool runOnCode(tooling::ToolAction *ToolAction, StringRef Code,
|
|||
static std::string runIncludeFixer(
|
||||
StringRef Code,
|
||||
const std::vector<std::string> &ExtraArgs = std::vector<std::string>()) {
|
||||
std::vector<SymbolInfo> Symbols = {
|
||||
SymbolInfo("string", SymbolInfo::SymbolKind::Class, "<string>", 1,
|
||||
{{SymbolInfo::ContextType::Namespace, "std"}}),
|
||||
SymbolInfo("sting", SymbolInfo::SymbolKind::Class, "\"sting\"", 1,
|
||||
{{SymbolInfo::ContextType::Namespace, "std"}}),
|
||||
SymbolInfo("foo", SymbolInfo::SymbolKind::Class, "\"dir/otherdir/qux.h\"",
|
||||
1, {{SymbolInfo::ContextType::Namespace, "b"},
|
||||
{SymbolInfo::ContextType::Namespace, "a"}}),
|
||||
SymbolInfo("bar", SymbolInfo::SymbolKind::Class, "\"bar.h\"", 1,
|
||||
{{SymbolInfo::ContextType::Namespace, "b"},
|
||||
{SymbolInfo::ContextType::Namespace, "a"}}),
|
||||
SymbolInfo("bar", SymbolInfo::SymbolKind::Class, "\"bar2.h\"", 1,
|
||||
{{SymbolInfo::ContextType::Namespace, "c"},
|
||||
{SymbolInfo::ContextType::Namespace, "a"}}),
|
||||
SymbolInfo("Green", SymbolInfo::SymbolKind::Class, "\"color.h\"", 1,
|
||||
{{SymbolInfo::ContextType::EnumDecl, "Color"},
|
||||
{SymbolInfo::ContextType::Namespace, "b"},
|
||||
{SymbolInfo::ContextType::Namespace, "a"}}),
|
||||
SymbolInfo("Vector", SymbolInfo::SymbolKind::Class, "\"Vector.h\"", 1,
|
||||
{{SymbolInfo::ContextType::Namespace, "__a"},
|
||||
{SymbolInfo::ContextType::Namespace, "a"}},
|
||||
/*num_occurrences=*/2),
|
||||
SymbolInfo("Vector", SymbolInfo::SymbolKind::Class, "\"Vector.h\"", 2,
|
||||
{{SymbolInfo::ContextType::Namespace, "a"}},
|
||||
/*num_occurrences=*/1),
|
||||
SymbolInfo("StrCat", SymbolInfo::SymbolKind::Class, "\"strcat.h\"",
|
||||
1, {{SymbolInfo::ContextType::Namespace, "str"}}),
|
||||
SymbolInfo("str", SymbolInfo::SymbolKind::Class, "\"str.h\"",
|
||||
1, {}),
|
||||
SymbolInfo("foo2", SymbolInfo::SymbolKind::Class, "\"foo2.h\"",
|
||||
1, {}),
|
||||
std::vector<SymbolAndSignals> Symbols = {
|
||||
{SymbolInfo("string", SymbolInfo::SymbolKind::Class, "<string>", 1,
|
||||
{{SymbolInfo::ContextType::Namespace, "std"}}),
|
||||
SymbolInfo::Signals{}},
|
||||
{SymbolInfo("sting", SymbolInfo::SymbolKind::Class, "\"sting\"", 1,
|
||||
{{SymbolInfo::ContextType::Namespace, "std"}}),
|
||||
SymbolInfo::Signals{}},
|
||||
{SymbolInfo("foo", SymbolInfo::SymbolKind::Class,
|
||||
"\"dir/otherdir/qux.h\"", 1,
|
||||
{{SymbolInfo::ContextType::Namespace, "b"},
|
||||
{SymbolInfo::ContextType::Namespace, "a"}}),
|
||||
SymbolInfo::Signals{}},
|
||||
{SymbolInfo("bar", SymbolInfo::SymbolKind::Class, "\"bar.h\"", 1,
|
||||
{{SymbolInfo::ContextType::Namespace, "b"},
|
||||
{SymbolInfo::ContextType::Namespace, "a"}}),
|
||||
SymbolInfo::Signals{}},
|
||||
{SymbolInfo("bar", SymbolInfo::SymbolKind::Class, "\"bar2.h\"", 1,
|
||||
{{SymbolInfo::ContextType::Namespace, "c"},
|
||||
{SymbolInfo::ContextType::Namespace, "a"}}),
|
||||
SymbolInfo::Signals{}},
|
||||
{SymbolInfo("Green", SymbolInfo::SymbolKind::Class, "\"color.h\"", 1,
|
||||
{{SymbolInfo::ContextType::EnumDecl, "Color"},
|
||||
{SymbolInfo::ContextType::Namespace, "b"},
|
||||
{SymbolInfo::ContextType::Namespace, "a"}}),
|
||||
SymbolInfo::Signals{}},
|
||||
{SymbolInfo("Vector", SymbolInfo::SymbolKind::Class, "\"Vector.h\"", 1,
|
||||
{{SymbolInfo::ContextType::Namespace, "__a"},
|
||||
{SymbolInfo::ContextType::Namespace, "a"}}),
|
||||
SymbolInfo::Signals{/*Seen=*/2, 0}},
|
||||
{SymbolInfo("Vector", SymbolInfo::SymbolKind::Class, "\"Vector.h\"", 2,
|
||||
{{SymbolInfo::ContextType::Namespace, "a"}}),
|
||||
SymbolInfo::Signals{/*Seen=*/2, 0}},
|
||||
{SymbolInfo("StrCat", SymbolInfo::SymbolKind::Class, "\"strcat.h\"", 1,
|
||||
{{SymbolInfo::ContextType::Namespace, "str"}}),
|
||||
SymbolInfo::Signals{}},
|
||||
{SymbolInfo("str", SymbolInfo::SymbolKind::Class, "\"str.h\"", 1, {}),
|
||||
SymbolInfo::Signals{}},
|
||||
{SymbolInfo("foo2", SymbolInfo::SymbolKind::Class, "\"foo2.h\"", 1, {}),
|
||||
SymbolInfo::Signals{}},
|
||||
};
|
||||
auto SymbolIndexMgr = llvm::make_unique<include_fixer::SymbolIndexManager>();
|
||||
SymbolIndexMgr->addSymbolIndex([=]() {
|
||||
return llvm::make_unique<include_fixer::InMemorySymbolIndex>(Symbols);
|
||||
});
|
||||
auto SymbolIndexMgr = llvm::make_unique<SymbolIndexManager>();
|
||||
SymbolIndexMgr->addSymbolIndex(
|
||||
[=]() { return llvm::make_unique<InMemorySymbolIndex>(Symbols); });
|
||||
|
||||
std::vector<IncludeFixerContext> FixerContexts;
|
||||
IncludeFixerActionFactory Factory(*SymbolIndexMgr, FixerContexts, "llvm");
|
||||
|
@ -96,15 +104,14 @@ static std::string runIncludeFixer(
|
|||
assert(FixerContexts.size() == 1);
|
||||
if (FixerContexts.front().getHeaderInfos().empty())
|
||||
return Code;
|
||||
auto Replaces = clang::include_fixer::createIncludeFixerReplacements(
|
||||
Code, FixerContexts.front());
|
||||
auto Replaces = createIncludeFixerReplacements(Code, FixerContexts.front());
|
||||
EXPECT_TRUE(static_cast<bool>(Replaces))
|
||||
<< llvm::toString(Replaces.takeError()) << "\n";
|
||||
if (!Replaces)
|
||||
return "";
|
||||
clang::RewriterTestContext Context;
|
||||
clang::FileID ID = Context.createInMemoryFile(FakeFileName, Code);
|
||||
clang::tooling::applyAllReplacements(*Replaces, Context.Rewrite);
|
||||
RewriterTestContext Context;
|
||||
FileID ID = Context.createInMemoryFile(FakeFileName, Code);
|
||||
tooling::applyAllReplacements(*Replaces, Context.Rewrite);
|
||||
return Context.getRewrittenText(ID);
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "clang/Frontend/PCHContainerOperations.h"
|
||||
#include "clang/Tooling/Tooling.h"
|
||||
#include "llvm/ADT/IntrusiveRefCntPtr.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
@ -31,25 +32,28 @@ namespace find_all_symbols {
|
|||
|
||||
static const char HeaderName[] = "symbols.h";
|
||||
|
||||
class TestSymbolReporter : public clang::find_all_symbols::SymbolReporter {
|
||||
class TestSymbolReporter : public SymbolReporter {
|
||||
public:
|
||||
~TestSymbolReporter() override {}
|
||||
|
||||
void reportSymbol(llvm::StringRef FileName,
|
||||
const SymbolInfo &Symbol) override {
|
||||
Symbols.push_back(Symbol);
|
||||
void reportSymbols(llvm::StringRef FileName,
|
||||
const SymbolInfo::SignalMap &NewSymbols) override {
|
||||
for (const auto &Entry : NewSymbols)
|
||||
Symbols[Entry.first] += Entry.second;
|
||||
}
|
||||
|
||||
bool hasSymbol(const SymbolInfo &Symbol) const {
|
||||
for (const auto &S : Symbols) {
|
||||
if (S == Symbol)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
auto it = Symbols.find(Symbol);
|
||||
return it != Symbols.end() && it->second.Seen > 0;
|
||||
}
|
||||
|
||||
bool hasUse(const SymbolInfo &Symbol) const {
|
||||
auto it = Symbols.find(Symbol);
|
||||
return it != Symbols.end() && it->second.Used > 0;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<SymbolInfo> Symbols;
|
||||
SymbolInfo::SignalMap Symbols;
|
||||
};
|
||||
|
||||
class FindAllSymbolsTest : public ::testing::Test {
|
||||
|
@ -58,7 +62,9 @@ public:
|
|||
return Reporter.hasSymbol(Symbol);
|
||||
}
|
||||
|
||||
bool runFindAllSymbols(StringRef Code) {
|
||||
bool hasUse(const SymbolInfo &Symbol) { return Reporter.hasUse(Symbol); }
|
||||
|
||||
bool runFindAllSymbols(StringRef HeaderCode, StringRef MainCode) {
|
||||
llvm::IntrusiveRefCntPtr<vfs::InMemoryFileSystem> InMemoryFileSystem(
|
||||
new vfs::InMemoryFileSystem);
|
||||
llvm::IntrusiveRefCntPtr<FileManager> Files(
|
||||
|
@ -88,7 +94,7 @@ public:
|
|||
InMemoryFileSystem->addFile(InternalHeader, 0,
|
||||
llvm::MemoryBuffer::getMemBuffer(InternalCode));
|
||||
|
||||
std::unique_ptr<clang::tooling::FrontendActionFactory> Factory(
|
||||
std::unique_ptr<tooling::FrontendActionFactory> Factory(
|
||||
new FindAllSymbolsActionFactory(&Reporter, &RegexMap));
|
||||
|
||||
tooling::ToolInvocation Invocation(
|
||||
|
@ -98,7 +104,7 @@ public:
|
|||
std::make_shared<PCHContainerOperations>());
|
||||
|
||||
InMemoryFileSystem->addFile(HeaderName, 0,
|
||||
llvm::MemoryBuffer::getMemBuffer(Code));
|
||||
llvm::MemoryBuffer::getMemBuffer(HeaderCode));
|
||||
|
||||
std::string Content = "#include\"" + std::string(HeaderName) +
|
||||
"\"\n"
|
||||
|
@ -118,6 +124,7 @@ public:
|
|||
SymbolInfo DirtySymbol("ExtraInternal", SymbolInfo::SymbolKind::Class,
|
||||
CleanHeader, 2, {});
|
||||
#endif // _MSC_VER && __MINGW32__
|
||||
Content += "\n" + MainCode.str();
|
||||
InMemoryFileSystem->addFile(FileName, 0,
|
||||
llvm::MemoryBuffer::getMemBuffer(Content));
|
||||
Invocation.run();
|
||||
|
@ -135,49 +142,64 @@ protected:
|
|||
};
|
||||
|
||||
TEST_F(FindAllSymbolsTest, VariableSymbols) {
|
||||
static const char Code[] = R"(
|
||||
static const char Header[] = R"(
|
||||
extern int xargc;
|
||||
namespace na {
|
||||
static bool SSSS = false;
|
||||
namespace nb { const long long *XXXX; }
|
||||
})";
|
||||
runFindAllSymbols(Code);
|
||||
static const char Main[] = R"(
|
||||
auto y = &na::nb::XXXX;
|
||||
int main() { if (na::SSSS) return xargc; }
|
||||
)";
|
||||
runFindAllSymbols(Header, Main);
|
||||
|
||||
SymbolInfo Symbol =
|
||||
SymbolInfo("xargc", SymbolInfo::SymbolKind::Variable, HeaderName, 2, {});
|
||||
EXPECT_TRUE(hasSymbol(Symbol));
|
||||
EXPECT_TRUE(hasUse(Symbol));
|
||||
|
||||
Symbol = SymbolInfo("SSSS", SymbolInfo::SymbolKind::Variable, HeaderName, 4,
|
||||
{{SymbolInfo::ContextType::Namespace, "na"}});
|
||||
EXPECT_TRUE(hasSymbol(Symbol));
|
||||
EXPECT_TRUE(hasUse(Symbol));
|
||||
|
||||
Symbol = SymbolInfo("XXXX", SymbolInfo::SymbolKind::Variable, HeaderName, 5,
|
||||
{{SymbolInfo::ContextType::Namespace, "nb"},
|
||||
{SymbolInfo::ContextType::Namespace, "na"}});
|
||||
EXPECT_TRUE(hasSymbol(Symbol));
|
||||
EXPECT_TRUE(hasUse(Symbol));
|
||||
}
|
||||
|
||||
TEST_F(FindAllSymbolsTest, ExternCSymbols) {
|
||||
static const char Code[] = R"(
|
||||
static const char Header[] = R"(
|
||||
extern "C" {
|
||||
int C_Func() { return 0; }
|
||||
struct C_struct {
|
||||
int Member;
|
||||
};
|
||||
})";
|
||||
runFindAllSymbols(Code);
|
||||
static const char Main[] = R"(
|
||||
C_struct q() {
|
||||
int(*ptr)() = C_Func;
|
||||
return {0};
|
||||
}
|
||||
)";
|
||||
runFindAllSymbols(Header, Main);
|
||||
|
||||
SymbolInfo Symbol =
|
||||
SymbolInfo("C_Func", SymbolInfo::SymbolKind::Function, HeaderName, 3, {});
|
||||
EXPECT_TRUE(hasSymbol(Symbol));
|
||||
EXPECT_TRUE(hasUse(Symbol));
|
||||
|
||||
Symbol =
|
||||
SymbolInfo("C_struct", SymbolInfo::SymbolKind::Class, HeaderName, 4, {});
|
||||
EXPECT_TRUE(hasSymbol(Symbol));
|
||||
EXPECT_TRUE(hasUse(Symbol));
|
||||
}
|
||||
|
||||
TEST_F(FindAllSymbolsTest, CXXRecordSymbols) {
|
||||
static const char Code[] = R"(
|
||||
static const char Header[] = R"(
|
||||
struct Glob {};
|
||||
struct A; // Not a defintion, ignored.
|
||||
class NOP; // Not a defintion, ignored
|
||||
|
@ -190,26 +212,33 @@ TEST_F(FindAllSymbolsTest, CXXRecordSymbols) {
|
|||
};
|
||||
}; //
|
||||
)";
|
||||
runFindAllSymbols(Code);
|
||||
static const char Main[] = R"(
|
||||
static Glob glob;
|
||||
static na::A::AAAA* a;
|
||||
)";
|
||||
runFindAllSymbols(Header, Main);
|
||||
|
||||
SymbolInfo Symbol =
|
||||
SymbolInfo("Glob", SymbolInfo::SymbolKind::Class, HeaderName, 2, {});
|
||||
EXPECT_TRUE(hasSymbol(Symbol));
|
||||
EXPECT_TRUE(hasUse(Symbol));
|
||||
|
||||
Symbol = SymbolInfo("A", SymbolInfo::SymbolKind::Class, HeaderName, 6,
|
||||
{{SymbolInfo::ContextType::Namespace, "na"}});
|
||||
EXPECT_TRUE(hasSymbol(Symbol));
|
||||
EXPECT_TRUE(hasUse(Symbol));
|
||||
|
||||
Symbol = SymbolInfo("AAA", SymbolInfo::SymbolKind::Class, HeaderName, 7,
|
||||
{{SymbolInfo::ContextType::Record, "A"},
|
||||
{SymbolInfo::ContextType::Namespace, "na"}});
|
||||
EXPECT_FALSE(hasSymbol(Symbol));
|
||||
EXPECT_FALSE(hasUse(Symbol));
|
||||
}
|
||||
|
||||
TEST_F(FindAllSymbolsTest, CXXRecordSymbolsTemplate) {
|
||||
static const char Code[] = R"(
|
||||
static const char Header[] = R"(
|
||||
template <typename T>
|
||||
class T_TEMP {
|
||||
struct T_TEMP {
|
||||
template <typename _Tp1>
|
||||
struct rebind { typedef T_TEMP<_Tp1> other; };
|
||||
};
|
||||
|
@ -222,11 +251,15 @@ TEST_F(FindAllSymbolsTest, CXXRecordSymbolsTemplate) {
|
|||
// Ignore specialization.
|
||||
template <> class Observer<int> {};
|
||||
)";
|
||||
runFindAllSymbols(Code);
|
||||
static const char Main[] = R"(
|
||||
extern T_TEMP<int>::rebind<char> weirdo;
|
||||
)";
|
||||
runFindAllSymbols(Header, Main);
|
||||
|
||||
SymbolInfo Symbol =
|
||||
SymbolInfo("T_TEMP", SymbolInfo::SymbolKind::Class, HeaderName, 3, {});
|
||||
EXPECT_TRUE(hasSymbol(Symbol));
|
||||
EXPECT_TRUE(hasUse(Symbol));
|
||||
}
|
||||
|
||||
TEST_F(FindAllSymbolsTest, DontIgnoreTemplatePartialSpecialization) {
|
||||
|
@ -239,7 +272,7 @@ TEST_F(FindAllSymbolsTest, DontIgnoreTemplatePartialSpecialization) {
|
|||
template<class T> void f() {};
|
||||
template<> void f<int>() {};
|
||||
)";
|
||||
runFindAllSymbols(Code);
|
||||
runFindAllSymbols(Code, "");
|
||||
SymbolInfo Symbol =
|
||||
SymbolInfo("Class", SymbolInfo::SymbolKind::Class, HeaderName, 4, {});
|
||||
EXPECT_TRUE(hasSymbol(Symbol));
|
||||
|
@ -252,7 +285,7 @@ TEST_F(FindAllSymbolsTest, DontIgnoreTemplatePartialSpecialization) {
|
|||
}
|
||||
|
||||
TEST_F(FindAllSymbolsTest, FunctionSymbols) {
|
||||
static const char Code[] = R"(
|
||||
static const char Header[] = R"(
|
||||
namespace na {
|
||||
int gg(int);
|
||||
int f(const int &a) { int Local; static int StaticLocal; return 0; }
|
||||
|
@ -265,91 +298,127 @@ TEST_F(FindAllSymbolsTest, FunctionSymbols) {
|
|||
} // namespace nb
|
||||
} // namespace na";
|
||||
)";
|
||||
runFindAllSymbols(Code);
|
||||
static const char Main[] = R"(
|
||||
int(*gg)(int) = &na::gg;
|
||||
int main() {
|
||||
(void)na::SSSFFF;
|
||||
na::nb::fun(0);
|
||||
return na::f(gg(0));
|
||||
}
|
||||
)";
|
||||
runFindAllSymbols(Header, Main);
|
||||
|
||||
SymbolInfo Symbol =
|
||||
SymbolInfo("gg", SymbolInfo::SymbolKind::Function, HeaderName, 3,
|
||||
{{SymbolInfo::ContextType::Namespace, "na"}});
|
||||
EXPECT_TRUE(hasSymbol(Symbol));
|
||||
EXPECT_TRUE(hasUse(Symbol));
|
||||
|
||||
Symbol = SymbolInfo("f", SymbolInfo::SymbolKind::Function, HeaderName, 4,
|
||||
{{SymbolInfo::ContextType::Namespace, "na"}});
|
||||
EXPECT_TRUE(hasSymbol(Symbol));
|
||||
EXPECT_TRUE(hasUse(Symbol));
|
||||
|
||||
Symbol = SymbolInfo("SSSFFF", SymbolInfo::SymbolKind::Function, HeaderName, 5,
|
||||
{{SymbolInfo::ContextType::Namespace, "na"}});
|
||||
EXPECT_TRUE(hasSymbol(Symbol));
|
||||
EXPECT_TRUE(hasUse(Symbol));
|
||||
|
||||
Symbol = SymbolInfo("fun", SymbolInfo::SymbolKind::Function, HeaderName, 10,
|
||||
{{SymbolInfo::ContextType::Namespace, "nb"},
|
||||
{SymbolInfo::ContextType::Namespace, "na"}});
|
||||
EXPECT_TRUE(hasSymbol(Symbol));
|
||||
EXPECT_TRUE(hasUse(Symbol));
|
||||
}
|
||||
|
||||
TEST_F(FindAllSymbolsTest, NamespaceTest) {
|
||||
static const char Code[] = R"(
|
||||
static const char Header[] = R"(
|
||||
int X1;
|
||||
namespace { int X2; }
|
||||
namespace { namespace { int X3; } }
|
||||
namespace { namespace nb { int X4; } }
|
||||
namespace na { inline namespace __1 { int X5; } }
|
||||
)";
|
||||
runFindAllSymbols(Code);
|
||||
static const char Main[] = R"(
|
||||
using namespace nb;
|
||||
int main() {
|
||||
X1 = X2;
|
||||
X3 = X4;
|
||||
(void)na::X5;
|
||||
}
|
||||
)";
|
||||
runFindAllSymbols(Header, Main);
|
||||
|
||||
SymbolInfo Symbol =
|
||||
SymbolInfo("X1", SymbolInfo::SymbolKind::Variable, HeaderName, 2, {});
|
||||
EXPECT_TRUE(hasSymbol(Symbol));
|
||||
EXPECT_TRUE(hasUse(Symbol));
|
||||
|
||||
Symbol = SymbolInfo("X2", SymbolInfo::SymbolKind::Variable, HeaderName, 3,
|
||||
{{SymbolInfo::ContextType::Namespace, ""}});
|
||||
EXPECT_TRUE(hasSymbol(Symbol));
|
||||
EXPECT_TRUE(hasUse(Symbol));
|
||||
|
||||
Symbol = SymbolInfo("X3", SymbolInfo::SymbolKind::Variable, HeaderName, 4,
|
||||
{{SymbolInfo::ContextType::Namespace, ""},
|
||||
{SymbolInfo::ContextType::Namespace, ""}});
|
||||
EXPECT_TRUE(hasSymbol(Symbol));
|
||||
EXPECT_TRUE(hasUse(Symbol));
|
||||
|
||||
Symbol = SymbolInfo("X4", SymbolInfo::SymbolKind::Variable, HeaderName, 5,
|
||||
{{SymbolInfo::ContextType::Namespace, "nb"},
|
||||
{SymbolInfo::ContextType::Namespace, ""}});
|
||||
EXPECT_TRUE(hasSymbol(Symbol));
|
||||
EXPECT_TRUE(hasUse(Symbol));
|
||||
|
||||
Symbol = SymbolInfo("X5", SymbolInfo::SymbolKind::Variable, HeaderName, 6,
|
||||
{{SymbolInfo::ContextType::Namespace, "na"}});
|
||||
EXPECT_TRUE(hasSymbol(Symbol));
|
||||
EXPECT_TRUE(hasUse(Symbol));
|
||||
}
|
||||
|
||||
TEST_F(FindAllSymbolsTest, DecayedTypeTest) {
|
||||
static const char Code[] = "void DecayedFunc(int x[], int y[10]) {}";
|
||||
runFindAllSymbols(Code);
|
||||
static const char Header[] = "void DecayedFunc(int x[], int y[10]) {}";
|
||||
static const char Main[] = R"(int main() { DecayedFunc(nullptr, nullptr); })";
|
||||
runFindAllSymbols(Header, Main);
|
||||
SymbolInfo Symbol = SymbolInfo(
|
||||
"DecayedFunc", SymbolInfo::SymbolKind::Function, HeaderName, 1, {});
|
||||
EXPECT_TRUE(hasSymbol(Symbol));
|
||||
EXPECT_TRUE(hasUse(Symbol));
|
||||
}
|
||||
|
||||
TEST_F(FindAllSymbolsTest, CTypedefTest) {
|
||||
static const char Code[] = R"(
|
||||
static const char Header[] = R"(
|
||||
typedef unsigned size_t_;
|
||||
typedef struct { int x; } X;
|
||||
using XX = X;
|
||||
)";
|
||||
runFindAllSymbols(Code);
|
||||
static const char Main[] = R"(
|
||||
size_t_ f;
|
||||
template<typename T> struct vector{};
|
||||
vector<X> list;
|
||||
void foo(const XX&){}
|
||||
)";
|
||||
runFindAllSymbols(Header, Main);
|
||||
|
||||
SymbolInfo Symbol = SymbolInfo("size_t_", SymbolInfo::SymbolKind::TypedefName,
|
||||
HeaderName, 2, {});
|
||||
EXPECT_TRUE(hasSymbol(Symbol));
|
||||
EXPECT_TRUE(hasUse(Symbol));
|
||||
|
||||
Symbol =
|
||||
SymbolInfo("X", SymbolInfo::SymbolKind::TypedefName, HeaderName, 3, {});
|
||||
EXPECT_TRUE(hasSymbol(Symbol));
|
||||
EXPECT_TRUE(hasUse(Symbol));
|
||||
|
||||
Symbol =
|
||||
SymbolInfo("XX", SymbolInfo::SymbolKind::TypedefName, HeaderName, 4, {});
|
||||
EXPECT_TRUE(hasSymbol(Symbol));
|
||||
EXPECT_TRUE(hasUse(Symbol));
|
||||
}
|
||||
|
||||
TEST_F(FindAllSymbolsTest, EnumTest) {
|
||||
static const char Code[] = R"(
|
||||
static const char Header[] = R"(
|
||||
enum Glob_E { G1, G2 };
|
||||
enum class Altitude { high='h', low='l'};
|
||||
enum { A1, A2 };
|
||||
|
@ -359,42 +428,58 @@ TEST_F(FindAllSymbolsTest, EnumTest) {
|
|||
};
|
||||
enum DECL : int;
|
||||
)";
|
||||
runFindAllSymbols(Code);
|
||||
static const char Main[] = R"(
|
||||
static auto flags = G1 | G2;
|
||||
static auto alt = Altitude::high;
|
||||
static auto nested = A::X1;
|
||||
extern DECL whatever;
|
||||
static auto flags2 = A1 | A2;
|
||||
)";
|
||||
runFindAllSymbols(Header, Main);
|
||||
|
||||
SymbolInfo Symbol =
|
||||
SymbolInfo("Glob_E", SymbolInfo::SymbolKind::EnumDecl, HeaderName, 2, {});
|
||||
EXPECT_TRUE(hasSymbol(Symbol));
|
||||
EXPECT_FALSE(hasUse(Symbol));
|
||||
|
||||
Symbol =
|
||||
SymbolInfo("G1", SymbolInfo::SymbolKind::EnumConstantDecl, HeaderName, 2,
|
||||
{{SymbolInfo::ContextType::EnumDecl, "Glob_E"}});
|
||||
EXPECT_TRUE(hasSymbol(Symbol));
|
||||
EXPECT_TRUE(hasUse(Symbol));
|
||||
|
||||
Symbol =
|
||||
SymbolInfo("G2", SymbolInfo::SymbolKind::EnumConstantDecl, HeaderName, 2,
|
||||
{{SymbolInfo::ContextType::EnumDecl, "Glob_E"}});
|
||||
EXPECT_TRUE(hasSymbol(Symbol));
|
||||
EXPECT_TRUE(hasUse(Symbol));
|
||||
|
||||
Symbol = SymbolInfo("Altitude", SymbolInfo::SymbolKind::EnumDecl, HeaderName,
|
||||
3, {});
|
||||
EXPECT_TRUE(hasSymbol(Symbol));
|
||||
EXPECT_TRUE(hasUse(Symbol));
|
||||
Symbol =
|
||||
SymbolInfo("high", SymbolInfo::SymbolKind::EnumConstantDecl, HeaderName,
|
||||
3, {{SymbolInfo::ContextType::EnumDecl, "Altitude"}});
|
||||
EXPECT_FALSE(hasSymbol(Symbol));
|
||||
EXPECT_FALSE(hasUse(Symbol));
|
||||
|
||||
Symbol = SymbolInfo("A1", SymbolInfo::SymbolKind::EnumConstantDecl,
|
||||
HeaderName, 4, {{SymbolInfo::ContextType::EnumDecl, ""}});
|
||||
EXPECT_TRUE(hasSymbol(Symbol));
|
||||
EXPECT_TRUE(hasUse(Symbol));
|
||||
Symbol = SymbolInfo("A2", SymbolInfo::SymbolKind::EnumConstantDecl,
|
||||
HeaderName, 4, {{SymbolInfo::ContextType::EnumDecl, ""}});
|
||||
EXPECT_TRUE(hasSymbol(Symbol));
|
||||
EXPECT_TRUE(hasUse(Symbol));
|
||||
Symbol = SymbolInfo("", SymbolInfo::SymbolKind::EnumDecl, HeaderName, 4, {});
|
||||
EXPECT_FALSE(hasSymbol(Symbol));
|
||||
EXPECT_FALSE(hasUse(Symbol));
|
||||
|
||||
Symbol = SymbolInfo("A_ENUM", SymbolInfo::SymbolKind::EnumDecl, HeaderName, 7,
|
||||
{{SymbolInfo::ContextType::Record, "A"}});
|
||||
EXPECT_FALSE(hasSymbol(Symbol));
|
||||
EXPECT_FALSE(hasUse(Symbol));
|
||||
|
||||
Symbol = SymbolInfo("X1", SymbolInfo::SymbolKind::EnumDecl, HeaderName, 7,
|
||||
{{SymbolInfo::ContextType::EnumDecl, "A_ENUM"},
|
||||
|
@ -407,63 +492,83 @@ TEST_F(FindAllSymbolsTest, EnumTest) {
|
|||
}
|
||||
|
||||
TEST_F(FindAllSymbolsTest, IWYUPrivatePragmaTest) {
|
||||
static const char Code[] = R"(
|
||||
static const char Header[] = R"(
|
||||
// IWYU pragma: private, include "bar.h"
|
||||
struct Bar {
|
||||
};
|
||||
)";
|
||||
runFindAllSymbols(Code);
|
||||
static const char Main[] = R"(
|
||||
Bar bar;
|
||||
)";
|
||||
runFindAllSymbols(Header, Main);
|
||||
|
||||
SymbolInfo Symbol =
|
||||
SymbolInfo("Bar", SymbolInfo::SymbolKind::Class, "bar.h", 3, {});
|
||||
EXPECT_TRUE(hasSymbol(Symbol));
|
||||
EXPECT_TRUE(hasUse(Symbol));
|
||||
}
|
||||
|
||||
TEST_F(FindAllSymbolsTest, MacroTest) {
|
||||
static const char Code[] = R"(
|
||||
static const char Header[] = R"(
|
||||
#define X
|
||||
#define Y 1
|
||||
#define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
|
||||
)";
|
||||
runFindAllSymbols(Code);
|
||||
static const char Main[] = R"(
|
||||
#ifdef X
|
||||
int main() { return MAX(0,Y); }
|
||||
#endif
|
||||
)";
|
||||
runFindAllSymbols(Header, Main);
|
||||
SymbolInfo Symbol =
|
||||
SymbolInfo("X", SymbolInfo::SymbolKind::Macro, HeaderName, 2, {});
|
||||
EXPECT_TRUE(hasSymbol(Symbol));
|
||||
EXPECT_TRUE(hasUse(Symbol));
|
||||
|
||||
Symbol = SymbolInfo("Y", SymbolInfo::SymbolKind::Macro, HeaderName, 3, {});
|
||||
EXPECT_TRUE(hasSymbol(Symbol));
|
||||
EXPECT_TRUE(hasUse(Symbol));
|
||||
|
||||
Symbol = SymbolInfo("MAX", SymbolInfo::SymbolKind::Macro, HeaderName, 4, {});
|
||||
EXPECT_TRUE(hasSymbol(Symbol));
|
||||
EXPECT_TRUE(hasUse(Symbol));
|
||||
}
|
||||
|
||||
TEST_F(FindAllSymbolsTest, MacroTestWithIWYU) {
|
||||
static const char Code[] = R"(
|
||||
static const char Header[] = R"(
|
||||
// IWYU pragma: private, include "bar.h"
|
||||
#define X
|
||||
#define X 1
|
||||
#define Y 1
|
||||
#define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
|
||||
)";
|
||||
runFindAllSymbols(Code);
|
||||
static const char Main[] = R"(
|
||||
#ifdef X
|
||||
int main() { return MAX(0,Y); }
|
||||
#endif
|
||||
)";
|
||||
runFindAllSymbols(Header, Main);
|
||||
SymbolInfo Symbol =
|
||||
SymbolInfo("X", SymbolInfo::SymbolKind::Macro, "bar.h", 3, {});
|
||||
EXPECT_TRUE(hasSymbol(Symbol));
|
||||
EXPECT_TRUE(hasUse(Symbol));
|
||||
|
||||
Symbol = SymbolInfo("Y", SymbolInfo::SymbolKind::Macro, "bar.h", 4, {});
|
||||
EXPECT_TRUE(hasSymbol(Symbol));
|
||||
EXPECT_TRUE(hasUse(Symbol));
|
||||
|
||||
Symbol = SymbolInfo("MAX", SymbolInfo::SymbolKind::Macro, "bar.h", 5, {});
|
||||
EXPECT_TRUE(hasSymbol(Symbol));
|
||||
EXPECT_TRUE(hasUse(Symbol));
|
||||
}
|
||||
|
||||
TEST_F(FindAllSymbolsTest, NoFriendTest) {
|
||||
static const char Code[] = R"(
|
||||
static const char Header[] = R"(
|
||||
class WorstFriend {
|
||||
friend void Friend();
|
||||
friend class BestFriend;
|
||||
};
|
||||
)";
|
||||
runFindAllSymbols(Code);
|
||||
runFindAllSymbols(Header, "");
|
||||
SymbolInfo Symbol = SymbolInfo("WorstFriend", SymbolInfo::SymbolKind::Class,
|
||||
HeaderName, 2, {});
|
||||
EXPECT_TRUE(hasSymbol(Symbol));
|
||||
|
|
Loading…
Reference in New Issue