[analyzer][CrossTU] Extend CTU to VarDecls with initializer

Summary:
The existing CTU mechanism imports `FunctionDecl`s where the definition is available in another TU. This patch extends that to VarDecls, to bind more constants.

- Add VarDecl importing functionality to CrossTranslationUnitContext
- Import Decls while traversing them in AnalysisConsumer
- Add VarDecls to CTU external mappings generator
- Name changes from "external function map" to "external definition map"

Reviewers: NoQ, dcoughlin, xazax.hun, george.karpenkov, martong

Reviewed By: xazax.hun

Subscribers: Charusso, baloghadamsoftware, mikhail.ramalho, Szelethus, donat.nagy, dkrupp, george.karpenkov, mgorny, whisperity, szepet, rnkovacs, a.sidorin, cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D46421

llvm-svn: 358968
This commit is contained in:
Rafael Stahl 2019-04-23 11:04:41 +00:00
parent 330bc8af13
commit 850361f6c1
10 changed files with 335 additions and 87 deletions

View File

@ -28,6 +28,7 @@ class ASTImporter;
class ASTUnit;
class DeclContext;
class FunctionDecl;
class VarDecl;
class NamedDecl;
class TranslationUnitDecl;
@ -87,6 +88,9 @@ parseCrossTUIndex(StringRef IndexPath, StringRef CrossTUDir);
std::string createCrossTUIndexString(const llvm::StringMap<std::string> &Index);
// Returns true if the variable or any field of a record variable is const.
bool containsConst(const VarDecl *VD, const ASTContext &ACtx);
/// This class is used for tools that requires cross translation
/// unit capability.
///
@ -102,16 +106,16 @@ public:
CrossTranslationUnitContext(CompilerInstance &CI);
~CrossTranslationUnitContext();
/// This function loads a function definition from an external AST
/// file and merge it into the original AST.
/// This function loads a function or variable definition from an
/// external AST file and merges it into the original AST.
///
/// This method should only be used on functions that have no definitions in
/// This method should only be used on functions that have no definitions or
/// variables that have no initializer in
/// the current translation unit. A function definition with the same
/// declaration will be looked up in the index file which should be in the
/// \p CrossTUDir directory, called \p IndexName. In case the declaration is
/// found in the index the corresponding AST file will be loaded and the
/// definition of the function will be merged into the original AST using
/// the AST Importer.
/// definition will be merged into the original AST using the AST Importer.
///
/// \return The declaration with the definition will be returned.
/// If no suitable definition is found in the index file or multiple
@ -121,17 +125,19 @@ public:
llvm::Expected<const FunctionDecl *>
getCrossTUDefinition(const FunctionDecl *FD, StringRef CrossTUDir,
StringRef IndexName, bool DisplayCTUProgress = false);
llvm::Expected<const VarDecl *>
getCrossTUDefinition(const VarDecl *VD, StringRef CrossTUDir,
StringRef IndexName, bool DisplayCTUProgress = false);
/// This function loads a function definition from an external AST
/// file.
/// This function loads a definition from an external AST file.
///
/// A function definition with the same declaration will be looked up in the
/// A definition with the same declaration will be looked up in the
/// index file which should be in the \p CrossTUDir directory, called
/// \p IndexName. In case the declaration is found in the index the
/// corresponding AST file will be loaded.
///
/// \return Returns a pointer to the ASTUnit that contains the definition of
/// the looked up function or an Error.
/// the looked up name or an Error.
/// The returned pointer is never a nullptr.
///
/// Note that the AST files should also be in the \p CrossTUDir.
@ -146,8 +152,9 @@ public:
///
/// \return Returns the resulting definition or an error.
llvm::Expected<const FunctionDecl *> importDefinition(const FunctionDecl *FD);
llvm::Expected<const VarDecl *> importDefinition(const VarDecl *VD);
/// Get a name to identify a function.
/// Get a name to identify a named decl.
static std::string getLookupName(const NamedDecl *ND);
/// Emit diagnostics for the user for potential configuration errors.
@ -156,12 +163,20 @@ public:
private:
void lazyInitLookupTable(TranslationUnitDecl *ToTU);
ASTImporter &getOrCreateASTImporter(ASTContext &From);
const FunctionDecl *findFunctionInDeclContext(const DeclContext *DC,
StringRef LookupFnName);
template <typename T>
llvm::Expected<const T *> getCrossTUDefinitionImpl(const T *D,
StringRef CrossTUDir,
StringRef IndexName,
bool DisplayCTUProgress);
template <typename T>
const T *findDefInDeclContext(const DeclContext *DC,
StringRef LookupName);
template <typename T>
llvm::Expected<const T *> importDefinitionImpl(const T *D);
llvm::StringMap<std::unique_ptr<clang::ASTUnit>> FileASTUnitMap;
llvm::StringMap<clang::ASTUnit *> FunctionASTUnitMap;
llvm::StringMap<std::string> FunctionFileMap;
llvm::StringMap<clang::ASTUnit *> NameASTUnitMap;
llvm::StringMap<std::string> NameFileMap;
llvm::DenseMap<TranslationUnitDecl *, std::unique_ptr<ASTImporter>>
ASTUnitImporterMap;
CompilerInstance &CI;

View File

@ -158,6 +158,27 @@ createCrossTUIndexString(const llvm::StringMap<std::string> &Index) {
return Result.str();
}
bool containsConst(const VarDecl *VD, const ASTContext &ACtx) {
CanQualType CT = ACtx.getCanonicalType(VD->getType());
if (!CT.isConstQualified()) {
const RecordType *RTy = CT->getAs<RecordType>();
if (!RTy || !RTy->hasConstFields())
return false;
}
return true;
}
static bool hasBodyOrInit(const FunctionDecl *D, const FunctionDecl *&DefD) {
return D->hasBody(DefD);
}
static bool hasBodyOrInit(const VarDecl *D, const VarDecl *&DefD) {
return D->getAnyInitializer(DefD);
}
template <typename T> static bool hasBodyOrInit(const T *D) {
const T *Unused;
return hasBodyOrInit(D, Unused);
}
CrossTranslationUnitContext::CrossTranslationUnitContext(CompilerInstance &CI)
: CI(CI), Context(CI.getASTContext()) {}
@ -165,48 +186,50 @@ CrossTranslationUnitContext::~CrossTranslationUnitContext() {}
std::string CrossTranslationUnitContext::getLookupName(const NamedDecl *ND) {
SmallString<128> DeclUSR;
bool Ret = index::generateUSRForDecl(ND, DeclUSR); (void)Ret;
bool Ret = index::generateUSRForDecl(ND, DeclUSR);
(void)Ret;
assert(!Ret && "Unable to generate USR");
return DeclUSR.str();
}
/// Recursively visits the function decls of a DeclContext, and looks up a
/// function based on USRs.
const FunctionDecl *
CrossTranslationUnitContext::findFunctionInDeclContext(const DeclContext *DC,
StringRef LookupFnName) {
/// Recursively visits the decls of a DeclContext, and returns one with the
/// given USR.
template <typename T>
const T *
CrossTranslationUnitContext::findDefInDeclContext(const DeclContext *DC,
StringRef LookupName) {
assert(DC && "Declaration Context must not be null");
for (const Decl *D : DC->decls()) {
const auto *SubDC = dyn_cast<DeclContext>(D);
if (SubDC)
if (const auto *FD = findFunctionInDeclContext(SubDC, LookupFnName))
return FD;
if (const auto *ND = findDefInDeclContext<T>(SubDC, LookupName))
return ND;
const auto *ND = dyn_cast<FunctionDecl>(D);
const FunctionDecl *ResultDecl;
if (!ND || !ND->hasBody(ResultDecl))
const auto *ND = dyn_cast<T>(D);
const T *ResultDecl;
if (!ND || !hasBodyOrInit(ND, ResultDecl))
continue;
if (getLookupName(ResultDecl) != LookupFnName)
if (getLookupName(ResultDecl) != LookupName)
continue;
return ResultDecl;
}
return nullptr;
}
llvm::Expected<const FunctionDecl *>
CrossTranslationUnitContext::getCrossTUDefinition(const FunctionDecl *FD,
StringRef CrossTUDir,
StringRef IndexName,
bool DisplayCTUProgress) {
assert(FD && "FD is missing, bad call to this function!");
assert(!FD->hasBody() && "FD has a definition in current translation unit!");
template <typename T>
llvm::Expected<const T *> CrossTranslationUnitContext::getCrossTUDefinitionImpl(
const T *D, StringRef CrossTUDir, StringRef IndexName,
bool DisplayCTUProgress) {
assert(D && "D is missing, bad call to this function!");
assert(!hasBodyOrInit(D) &&
"D has a body or init in current translation unit!");
++NumGetCTUCalled;
const std::string LookupFnName = getLookupName(FD);
if (LookupFnName.empty())
const std::string LookupName = getLookupName(D);
if (LookupName.empty())
return llvm::make_error<IndexError>(
index_error_code::failed_to_generate_usr);
llvm::Expected<ASTUnit *> ASTUnitOrError =
loadExternalAST(LookupFnName, CrossTUDir, IndexName, DisplayCTUProgress);
loadExternalAST(LookupName, CrossTUDir, IndexName, DisplayCTUProgress);
if (!ASTUnitOrError)
return ASTUnitOrError.takeError();
ASTUnit *Unit = *ASTUnitOrError;
@ -262,12 +285,29 @@ CrossTranslationUnitContext::getCrossTUDefinition(const FunctionDecl *FD,
}
TranslationUnitDecl *TU = Unit->getASTContext().getTranslationUnitDecl();
if (const FunctionDecl *ResultDecl =
findFunctionInDeclContext(TU, LookupFnName))
if (const T *ResultDecl = findDefInDeclContext<T>(TU, LookupName))
return importDefinition(ResultDecl);
return llvm::make_error<IndexError>(index_error_code::failed_import);
}
llvm::Expected<const FunctionDecl *>
CrossTranslationUnitContext::getCrossTUDefinition(const FunctionDecl *FD,
StringRef CrossTUDir,
StringRef IndexName,
bool DisplayCTUProgress) {
return getCrossTUDefinitionImpl(FD, CrossTUDir, IndexName,
DisplayCTUProgress);
}
llvm::Expected<const VarDecl *>
CrossTranslationUnitContext::getCrossTUDefinition(const VarDecl *VD,
StringRef CrossTUDir,
StringRef IndexName,
bool DisplayCTUProgress) {
return getCrossTUDefinitionImpl(VD, CrossTUDir, IndexName,
DisplayCTUProgress);
}
void CrossTranslationUnitContext::emitCrossTUDiagnostics(const IndexError &IE) {
switch (IE.getCode()) {
case index_error_code::missing_index_file:
@ -294,14 +334,14 @@ void CrossTranslationUnitContext::emitCrossTUDiagnostics(const IndexError &IE) {
llvm::Expected<ASTUnit *> CrossTranslationUnitContext::loadExternalAST(
StringRef LookupName, StringRef CrossTUDir, StringRef IndexName,
bool DisplayCTUProgress) {
// FIXME: The current implementation only supports loading functions with
// FIXME: The current implementation only supports loading decls with
// a lookup name from a single translation unit. If multiple
// translation units contains functions with the same lookup name an
// translation units contains decls with the same lookup name an
// error will be returned.
ASTUnit *Unit = nullptr;
auto FnUnitCacheEntry = FunctionASTUnitMap.find(LookupName);
if (FnUnitCacheEntry == FunctionASTUnitMap.end()) {
if (FunctionFileMap.empty()) {
auto NameUnitCacheEntry = NameASTUnitMap.find(LookupName);
if (NameUnitCacheEntry == NameASTUnitMap.end()) {
if (NameFileMap.empty()) {
SmallString<256> IndexFile = CrossTUDir;
if (llvm::sys::path::is_absolute(IndexName))
IndexFile = IndexName;
@ -310,13 +350,13 @@ llvm::Expected<ASTUnit *> CrossTranslationUnitContext::loadExternalAST(
llvm::Expected<llvm::StringMap<std::string>> IndexOrErr =
parseCrossTUIndex(IndexFile, CrossTUDir);
if (IndexOrErr)
FunctionFileMap = *IndexOrErr;
NameFileMap = *IndexOrErr;
else
return IndexOrErr.takeError();
}
auto It = FunctionFileMap.find(LookupName);
if (It == FunctionFileMap.end()) {
auto It = NameFileMap.find(LookupName);
if (It == NameFileMap.end()) {
++NumNotInOtherTU;
return llvm::make_error<IndexError>(index_error_code::missing_definition);
}
@ -342,9 +382,9 @@ llvm::Expected<ASTUnit *> CrossTranslationUnitContext::loadExternalAST(
} else {
Unit = ASTCacheEntry->second.get();
}
FunctionASTUnitMap[LookupName] = Unit;
NameASTUnitMap[LookupName] = Unit;
} else {
Unit = FnUnitCacheEntry->second;
Unit = NameUnitCacheEntry->second;
}
if (!Unit)
return llvm::make_error<IndexError>(
@ -352,12 +392,13 @@ llvm::Expected<ASTUnit *> CrossTranslationUnitContext::loadExternalAST(
return Unit;
}
llvm::Expected<const FunctionDecl *>
CrossTranslationUnitContext::importDefinition(const FunctionDecl *FD) {
assert(FD->hasBody() && "Functions to be imported should have body.");
template <typename T>
llvm::Expected<const T *>
CrossTranslationUnitContext::importDefinitionImpl(const T *D) {
assert(hasBodyOrInit(D) && "Decls to be imported should have body or init.");
ASTImporter &Importer = getOrCreateASTImporter(FD->getASTContext());
auto ToDeclOrError = Importer.Import_New(FD);
ASTImporter &Importer = getOrCreateASTImporter(D->getASTContext());
auto ToDeclOrError = Importer.Import_New(D);
if (!ToDeclOrError) {
handleAllErrors(ToDeclOrError.takeError(),
[&](const ImportError &IE) {
@ -375,13 +416,23 @@ CrossTranslationUnitContext::importDefinition(const FunctionDecl *FD) {
});
return llvm::make_error<IndexError>(index_error_code::failed_import);
}
auto *ToDecl = cast<FunctionDecl>(*ToDeclOrError);
assert(ToDecl->hasBody() && "Imported function should have body.");
auto *ToDecl = cast<T>(*ToDeclOrError);
assert(hasBodyOrInit(ToDecl) && "Imported Decl should have body or init.");
++NumGetCTUSuccess;
return ToDecl;
}
llvm::Expected<const FunctionDecl *>
CrossTranslationUnitContext::importDefinition(const FunctionDecl *FD) {
return importDefinitionImpl(FD);
}
llvm::Expected<const VarDecl *>
CrossTranslationUnitContext::importDefinition(const VarDecl *VD) {
return importDefinitionImpl(VD);
}
void CrossTranslationUnitContext::lazyInitLookupTable(
TranslationUnitDecl *ToTU) {
if (!LookupTable)

View File

@ -1655,7 +1655,7 @@ SVal RegionStoreManager::getBindingForElement(RegionBindingsConstRef B,
const VarDecl *VD = VR->getDecl();
// Either the array or the array element has to be const.
if (VD->getType().isConstQualified() || R->getElementType().isConstQualified()) {
if (const Expr *Init = VD->getInit()) {
if (const Expr *Init = VD->getAnyInitializer()) {
if (const auto *InitList = dyn_cast<InitListExpr>(Init)) {
// The array index has to be known.
if (auto CI = R->getIndex().getAs<nonloc::ConcreteInt>()) {
@ -1745,7 +1745,7 @@ SVal RegionStoreManager::getBindingForField(RegionBindingsConstRef B,
unsigned Index = FD->getFieldIndex();
// Either the record variable or the field has to be const qualified.
if (RecordVarTy.isConstQualified() || Ty.isConstQualified())
if (const Expr *Init = VD->getInit())
if (const Expr *Init = VD->getAnyInitializer())
if (const auto *InitList = dyn_cast<InitListExpr>(Init)) {
if (Index < InitList->getNumInits()) {
if (const Expr *FieldInit = InitList->getInit(Index))
@ -1943,7 +1943,7 @@ SVal RegionStoreManager::getBindingForVar(RegionBindingsConstRef B,
// Is 'VD' declared constant? If so, retrieve the constant value.
if (VD->getType().isConstQualified()) {
if (const Expr *Init = VD->getInit()) {
if (const Expr *Init = VD->getAnyInitializer()) {
if (Optional<SVal> V = svalBuilder.getConstantVal(Init))
return *V;

View File

@ -342,6 +342,35 @@ public:
return true;
}
bool VisitVarDecl(VarDecl *VD) {
if (!Opts->IsNaiveCTUEnabled)
return true;
if (VD->hasExternalStorage() || VD->isStaticDataMember()) {
if (!cross_tu::containsConst(VD, *Ctx))
return true;
} else {
// Cannot be initialized in another TU.
return true;
}
if (VD->getAnyInitializer())
return true;
llvm::Expected<const VarDecl *> CTUDeclOrError =
CTU.getCrossTUDefinition(VD, Opts->CTUDir, Opts->CTUIndexName,
Opts->DisplayCTUProgress);
if (!CTUDeclOrError) {
handleAllErrors(CTUDeclOrError.takeError(),
[&](const cross_tu::IndexError &IE) {
CTU.emitCrossTUDiagnostics(IE);
});
}
return true;
}
bool VisitFunctionDecl(FunctionDecl *FD) {
IdentifierInfo *II = FD->getIdentifier();
if (II && II->getName().startswith("__inline"))

View File

@ -80,3 +80,41 @@ int other_macro_diag(int x) {
MACRODIAG();
return x;
}
extern const int extInt = 2;
namespace intns {
extern const int extInt = 3;
}
struct S {
int a;
};
extern const S extS = {.a = 4};
struct A {
static const int a;
};
const int A::a = 3;
struct SC {
const int a;
};
SC extSC = {.a = 8};
struct ST {
static struct SC sc;
};
struct SC ST::sc = {.a = 2};
struct SCNest {
struct SCN {
const int a;
} scn;
};
SCNest extSCN = {.scn = {.a = 9}};
SCNest::SCN extSubSCN = {.a = 1};
struct SCC {
SCC(int c) : a(c) {}
const int a;
};
SCC extSCC{7};
union U {
const int a;
const unsigned int b;
};
U extU = {.a = 4};

View File

@ -13,3 +13,13 @@ c:@N@chns@S@chcls@F@chf4#I# ctu-chain.cpp.ast
c:@N@chns@F@chf2#I# ctu-chain.cpp.ast
c:@F@fun_using_anon_struct#I# ctu-other.cpp.ast
c:@F@other_macro_diag#I# ctu-other.cpp.ast
c:@extInt ctu-other.cpp.ast
c:@N@intns@extInt ctu-other.cpp.ast
c:@extS ctu-other.cpp.ast
c:@S@A@a ctu-other.cpp.ast
c:@extSC ctu-other.cpp.ast
c:@S@ST@sc ctu-other.cpp.ast
c:@extSCN ctu-other.cpp.ast
c:@extSubSCN ctu-other.cpp.ast
c:@extSCC ctu-other.cpp.ast
c:@extU ctu-other.cpp.ast

View File

@ -60,6 +60,44 @@ int chf1(int x);
int fun_using_anon_struct(int);
int other_macro_diag(int);
extern const int extInt;
namespace intns {
extern const int extInt;
}
struct S {
int a;
};
extern const S extS;
extern const int extHere;
const int extHere = 6;
struct A {
static const int a;
};
struct SC {
const int a;
};
extern SC extSC;
struct ST {
static struct SC sc;
};
struct SCNest {
struct SCN {
const int a;
} scn;
};
extern SCNest extSCN;
extern SCNest::SCN extSubSCN;
struct SCC {
SCC(int c);
const int a;
};
extern SCC extSCC;
union U {
const int a;
const unsigned int b;
};
extern U extU;
int main() {
clang_analyzer_eval(f(3) == 2); // expected-warning{{TRUE}}
clang_analyzer_eval(f(4) == 3); // expected-warning{{TRUE}}
@ -80,4 +118,16 @@ int main() {
clang_analyzer_eval(other_macro_diag(1) == 1); // expected-warning{{TRUE}}
// expected-warning@Inputs/ctu-other.cpp:80{{REACHABLE}}
MACRODIAG(); // expected-warning{{REACHABLE}}
clang_analyzer_eval(extInt == 2); // expected-warning{{TRUE}}
clang_analyzer_eval(intns::extInt == 3); // expected-warning{{TRUE}}
clang_analyzer_eval(extS.a == 4); // expected-warning{{TRUE}}
clang_analyzer_eval(extHere == 6); // expected-warning{{TRUE}}
clang_analyzer_eval(A::a == 3); // expected-warning{{TRUE}}
clang_analyzer_eval(extSC.a == 8); // expected-warning{{TRUE}}
clang_analyzer_eval(ST::sc.a == 2); // expected-warning{{TRUE}}
// clang_analyzer_eval(extSCN.scn.a == 9); // TODO
clang_analyzer_eval(extSubSCN.a == 1); // expected-warning{{TRUE}}
// clang_analyzer_eval(extSCC.a == 7); // TODO
clang_analyzer_eval(extU.a == 4); // expected-warning{{TRUE}}
}

View File

@ -1,7 +1,43 @@
// RUN: %clang_extdef_map %s -- | FileCheck %s
// RUN: %clang_extdef_map %s -- | FileCheck --implicit-check-not "c:@y" --implicit-check-not "c:@z" %s
int f(int) {
return 0;
}
// CHECK-DAG: c:@F@f#I#
// CHECK: c:@F@f#I#
extern const int x = 5;
// CHECK-DAG: c:@x
// Non-const variables should not be collected.
int y = 5;
// In C++, const implies internal linkage, so not collected.
const int z = 5;
struct S {
int a;
};
extern S const s = {.a = 2};
// CHECK-DAG: c:@s
struct SF {
const int a;
};
SF sf = {.a = 2};
// CHECK-DAG: c:@sf
struct SStatic {
static const int a = 4;
};
const int SStatic::a;
// CHECK-DAG: c:@S@SStatic@a
extern int const arr[5] = { 0, 1 };
// CHECK-DAG: c:@arr
union U {
const int a;
const unsigned int b;
};
U u = {.a = 6};
// CHECK-DAG: c:@u

View File

@ -0,0 +1,13 @@
// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify %s
// XFAIL: *
void clang_analyzer_eval(int);
extern const int extInt;
int main()
{
clang_analyzer_eval(extInt == 2); // expected-warning{{TRUE}}
}
extern const int extInt = 2;

View File

@ -34,20 +34,22 @@ static cl::OptionCategory ClangExtDefMapGenCategory("clang-extdefmapgen options"
class MapExtDefNamesConsumer : public ASTConsumer {
public:
MapExtDefNamesConsumer(ASTContext &Context)
: SM(Context.getSourceManager()) {}
: Ctx(Context), SM(Context.getSourceManager()) {}
~MapExtDefNamesConsumer() {
// Flush results to standard output.
llvm::outs() << createCrossTUIndexString(Index);
}
void HandleTranslationUnit(ASTContext &Ctx) override {
handleDecl(Ctx.getTranslationUnitDecl());
void HandleTranslationUnit(ASTContext &Context) override {
handleDecl(Context.getTranslationUnitDecl());
}
private:
void handleDecl(const Decl *D);
void addIfInMain(const DeclaratorDecl *DD, SourceLocation defStart);
ASTContext &Ctx;
SourceManager &SM;
llvm::StringMap<std::string> Index;
std::string CurrentFileName;
@ -58,30 +60,13 @@ void MapExtDefNamesConsumer::handleDecl(const Decl *D) {
return;
if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
if (FD->isThisDeclarationADefinition()) {
if (const Stmt *Body = FD->getBody()) {
if (CurrentFileName.empty()) {
CurrentFileName =
SM.getFileEntryForID(SM.getMainFileID())->tryGetRealPathName();
if (CurrentFileName.empty())
CurrentFileName = "invalid_file";
}
switch (FD->getLinkageInternal()) {
case ExternalLinkage:
case VisibleNoLinkage:
case UniqueExternalLinkage:
if (SM.isInMainFile(Body->getBeginLoc())) {
std::string LookupName =
CrossTranslationUnitContext::getLookupName(FD);
Index[LookupName] = CurrentFileName;
}
break;
default:
break;
}
}
}
if (FD->isThisDeclarationADefinition())
if (const Stmt *Body = FD->getBody())
addIfInMain(FD, Body->getBeginLoc());
} else if (const auto *VD = dyn_cast<VarDecl>(D)) {
if (cross_tu::containsConst(VD, Ctx) && VD->hasInit())
if (const Expr *Init = VD->getInit())
addIfInMain(VD, Init->getBeginLoc());
}
if (const auto *DC = dyn_cast<DeclContext>(D))
@ -89,6 +74,27 @@ void MapExtDefNamesConsumer::handleDecl(const Decl *D) {
handleDecl(D);
}
void MapExtDefNamesConsumer::addIfInMain(const DeclaratorDecl *DD,
SourceLocation defStart) {
std::string LookupName = CrossTranslationUnitContext::getLookupName(DD);
if (CurrentFileName.empty()) {
CurrentFileName =
SM.getFileEntryForID(SM.getMainFileID())->tryGetRealPathName();
if (CurrentFileName.empty())
CurrentFileName = "invalid_file";
}
switch (DD->getLinkageInternal()) {
case ExternalLinkage:
case VisibleNoLinkage:
case UniqueExternalLinkage:
if (SM.isInMainFile(defStart))
Index[LookupName] = CurrentFileName;
default:
break;
}
}
class MapExtDefNamesAction : public ASTFrontendAction {
protected:
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,