summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael Stahl <r.stahl@tum.de>2019-04-23 11:04:41 +0000
committerRafael Stahl <r.stahl@tum.de>2019-04-23 11:04:41 +0000
commit55bbda44b412f57f2bfa3f69c6ccaecc1acf3244 (patch)
tree48883aeb88c80642bf236b5520f986f472ca4d33
parenteb72871e0572587b9ab80c8abbb2845888f6b651 (diff)
[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 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@358968 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/CrossTU/CrossTranslationUnit.h43
-rw-r--r--lib/CrossTU/CrossTranslationUnit.cpp133
-rw-r--r--lib/StaticAnalyzer/Core/RegionStore.cpp6
-rw-r--r--lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp29
-rw-r--r--test/Analysis/Inputs/ctu-other.cpp38
-rw-r--r--test/Analysis/Inputs/ctu-other.cpp.externalDefMap.txt10
-rw-r--r--test/Analysis/ctu-main.cpp50
-rw-r--r--test/Analysis/func-mapping-test.cpp40
-rw-r--r--test/Analysis/redecl.c13
-rw-r--r--tools/clang-extdef-mapping/ClangExtDefMapGen.cpp60
10 files changed, 335 insertions, 87 deletions
diff --git a/include/clang/CrossTU/CrossTranslationUnit.h b/include/clang/CrossTU/CrossTranslationUnit.h
index bbbba7ad7b..9270f7fa7a 100644
--- a/include/clang/CrossTU/CrossTranslationUnit.h
+++ b/include/clang/CrossTU/CrossTranslationUnit.h
@@ -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;
diff --git a/lib/CrossTU/CrossTranslationUnit.cpp b/lib/CrossTU/CrossTranslationUnit.cpp
index 3e787419aa..9b68f3726e 100644
--- a/lib/CrossTU/CrossTranslationUnit.cpp
+++ b/lib/CrossTU/CrossTranslationUnit.cpp
@@ -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)
diff --git a/lib/StaticAnalyzer/Core/RegionStore.cpp b/lib/StaticAnalyzer/Core/RegionStore.cpp
index ffb25dc3d1..4e1c73b7e2 100644
--- a/lib/StaticAnalyzer/Core/RegionStore.cpp
+++ b/lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -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;
diff --git a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
index e2f6014fae..5c674923e0 100644
--- a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
+++ b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
@@ -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"))
diff --git a/test/Analysis/Inputs/ctu-other.cpp b/test/Analysis/Inputs/ctu-other.cpp
index c635cf6fc6..de7d064135 100644
--- a/test/Analysis/Inputs/ctu-other.cpp
+++ b/test/Analysis/Inputs/ctu-other.cpp
@@ -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};
diff --git a/test/Analysis/Inputs/ctu-other.cpp.externalDefMap.txt b/test/Analysis/Inputs/ctu-other.cpp.externalDefMap.txt
index 5461685dc6..57f4194831 100644
--- a/test/Analysis/Inputs/ctu-other.cpp.externalDefMap.txt
+++ b/test/Analysis/Inputs/ctu-other.cpp.externalDefMap.txt
@@ -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
diff --git a/test/Analysis/ctu-main.cpp b/test/Analysis/ctu-main.cpp
index 03a47dfe0b..a5de18bb3e 100644
--- a/test/Analysis/ctu-main.cpp
+++ b/test/Analysis/ctu-main.cpp
@@ -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}}
}
diff --git a/test/Analysis/func-mapping-test.cpp b/test/Analysis/func-mapping-test.cpp
index a5d7cfb449..f6eeb261da 100644
--- a/test/Analysis/func-mapping-test.cpp
+++ b/test/Analysis/func-mapping-test.cpp
@@ -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
diff --git a/test/Analysis/redecl.c b/test/Analysis/redecl.c
new file mode 100644
index 0000000000..f5771a7317
--- /dev/null
+++ b/test/Analysis/redecl.c
@@ -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;
diff --git a/tools/clang-extdef-mapping/ClangExtDefMapGen.cpp b/tools/clang-extdef-mapping/ClangExtDefMapGen.cpp
index 4cb9d08170..804745d285 100644
--- a/tools/clang-extdef-mapping/ClangExtDefMapGen.cpp
+++ b/tools/clang-extdef-mapping/ClangExtDefMapGen.cpp
@@ -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,