[analyzer][ctu] Only import const and trivial VarDecls

Do import the definition of objects from a foreign translation unit if that's type is const and trivial.

Differential Revision: https://reviews.llvm.org/D122805
This commit is contained in:
Gabor Marton 2022-04-01 11:58:17 +02:00
parent 111cb395c9
commit e63b81d10e
8 changed files with 36 additions and 22 deletions

View File

@ -109,8 +109,10 @@ llvm::Expected<InvocationListTy> parseInvocationList(
StringRef FileContent, StringRef FileContent,
llvm::sys::path::Style PathStyle = llvm::sys::path::Style::posix); llvm::sys::path::Style PathStyle = llvm::sys::path::Style::posix);
// Returns true if the variable or any field of a record variable is const. /// Returns true if it makes sense to import a foreign variable definition.
bool containsConst(const VarDecl *VD, const ASTContext &ACtx); /// For instance, we don't want to import variables that have non-trivial types
/// because the constructor might have side-effects.
bool shouldImport(const VarDecl *VD, const ASTContext &ACtx);
/// This class is used for tools that requires cross translation /// This class is used for tools that requires cross translation
/// unit capability. /// unit capability.

View File

@ -220,14 +220,9 @@ createCrossTUIndexString(const llvm::StringMap<std::string> &Index) {
return Result.str(); return Result.str();
} }
bool containsConst(const VarDecl *VD, const ASTContext &ACtx) { bool shouldImport(const VarDecl *VD, const ASTContext &ACtx) {
CanQualType CT = ACtx.getCanonicalType(VD->getType()); CanQualType CT = ACtx.getCanonicalType(VD->getType());
if (!CT.isConstQualified()) { return CT.isConstQualified() && VD->getType().isTrivialType(ACtx);
const RecordType *RTy = CT->getAs<RecordType>();
if (!RTy || !RTy->hasConstFields())
return false;
}
return true;
} }
static bool hasBodyOrInit(const FunctionDecl *D, const FunctionDecl *&DefD) { static bool hasBodyOrInit(const FunctionDecl *D, const FunctionDecl *&DefD) {

View File

@ -289,7 +289,7 @@ public:
return true; return true;
if (VD->hasExternalStorage() || VD->isStaticDataMember()) { if (VD->hasExternalStorage() || VD->isStaticDataMember()) {
if (!cross_tu::containsConst(VD, *Ctx)) if (!cross_tu::shouldImport(VD, *Ctx))
return true; return true;
} else { } else {
// Cannot be initialized in another TU. // Cannot be initialized in another TU.

View File

@ -102,6 +102,12 @@ struct S {
int a; int a;
}; };
extern const S extS = {.a = 4}; extern const S extS = {.a = 4};
extern S extNonConstS = {.a = 4};
struct NonTrivialS {
int a;
~NonTrivialS();
};
extern const NonTrivialS extNTS = {.a = 4};
struct A { struct A {
static const int a; static const int a;
}; };
@ -109,18 +115,18 @@ const int A::a = 3;
struct SC { struct SC {
const int a; const int a;
}; };
SC extSC = {.a = 8}; extern const SC extSC = {.a = 8};
struct ST { struct ST {
static struct SC sc; static const struct SC sc;
}; };
struct SC ST::sc = {.a = 2}; const struct SC ST::sc = {.a = 2};
struct SCNest { struct SCNest {
struct SCN { struct SCN {
const int a; const int a;
} scn; } scn;
}; };
SCNest extSCN = {.scn = {.a = 9}}; SCNest extSCN = {.scn = {.a = 9}};
SCNest::SCN extSubSCN = {.a = 1}; extern SCNest::SCN const extSubSCN = {.a = 1};
struct SCC { struct SCC {
SCC(int c) : a(c) {} SCC(int c) : a(c) {}
const int a; const int a;
@ -130,7 +136,7 @@ union U {
const int a; const int a;
const unsigned int b; const unsigned int b;
}; };
U extU = {.a = 4}; extern const U extU = {.a = 4};
class TestAnonUnionUSR { class TestAnonUnionUSR {
public: public:

View File

@ -18,6 +18,7 @@
9:c:@extInt ctu-other.cpp.ast 9:c:@extInt ctu-other.cpp.ast
17:c:@N@intns@extInt ctu-other.cpp.ast 17:c:@N@intns@extInt ctu-other.cpp.ast
7:c:@extS ctu-other.cpp.ast 7:c:@extS ctu-other.cpp.ast
9:c:@extNTS ctu-other.cpp.ast
8:c:@S@A@a ctu-other.cpp.ast 8:c:@S@A@a ctu-other.cpp.ast
8:c:@extSC ctu-other.cpp.ast 8:c:@extSC ctu-other.cpp.ast
10:c:@S@ST@sc ctu-other.cpp.ast 10:c:@S@ST@sc ctu-other.cpp.ast

View File

@ -74,6 +74,13 @@ struct S {
int a; int a;
}; };
extern const S extS; extern const S extS;
extern S extNonConstS;
struct NonTrivialS {
int a;
// User declaring a dtor makes it non-trivial.
~NonTrivialS();
};
extern const NonTrivialS extNTS;
extern const int extHere; extern const int extHere;
const int extHere = 6; const int extHere = 6;
struct A { struct A {
@ -82,9 +89,9 @@ struct A {
struct SC { struct SC {
const int a; const int a;
}; };
extern SC extSC; extern const SC extSC;
struct ST { struct ST {
static struct SC sc; static const struct SC sc;
}; };
struct SCNest { struct SCNest {
struct SCN { struct SCN {
@ -92,7 +99,7 @@ struct SCNest {
} scn; } scn;
}; };
extern SCNest extSCN; extern SCNest extSCN;
extern SCNest::SCN extSubSCN; extern const SCNest::SCN extSubSCN;
struct SCC { struct SCC {
SCC(int c); SCC(int c);
const int a; const int a;
@ -102,7 +109,7 @@ union U {
const int a; const int a;
const unsigned int b; const unsigned int b;
}; };
extern U extU; extern const U extU;
void test_virtual_functions(mycls* obj) { void test_virtual_functions(mycls* obj) {
// The dynamic type is known. // The dynamic type is known.
@ -153,6 +160,9 @@ int main() {
clang_analyzer_eval(extInt == 2); // expected-warning{{TRUE}} clang_analyzer_eval(extInt == 2); // expected-warning{{TRUE}}
clang_analyzer_eval(intns::extInt == 3); // expected-warning{{TRUE}} clang_analyzer_eval(intns::extInt == 3); // expected-warning{{TRUE}}
clang_analyzer_eval(extS.a == 4); // expected-warning{{TRUE}} clang_analyzer_eval(extS.a == 4); // expected-warning{{TRUE}}
clang_analyzer_eval(extNonConstS.a == 4); // expected-warning{{TRUE}} expected-warning{{FALSE}}
// Do not import non-trivial classes' initializers.
clang_analyzer_eval(extNTS.a == 4); // expected-warning{{TRUE}} expected-warning{{FALSE}}
clang_analyzer_eval(extHere == 6); // expected-warning{{TRUE}} clang_analyzer_eval(extHere == 6); // expected-warning{{TRUE}}
clang_analyzer_eval(A::a == 3); // expected-warning{{TRUE}} clang_analyzer_eval(A::a == 3); // expected-warning{{TRUE}}
clang_analyzer_eval(extSC.a == 8); // expected-warning{{TRUE}} clang_analyzer_eval(extSC.a == 8); // expected-warning{{TRUE}}

View File

@ -23,7 +23,7 @@ extern S const s = {.a = 2};
struct SF { struct SF {
const int a; const int a;
}; };
SF sf = {.a = 2}; extern const SF sf = {.a = 2};
// CHECK-DAG: 5:c:@sf // CHECK-DAG: 5:c:@sf
struct SStatic { struct SStatic {
@ -39,7 +39,7 @@ union U {
const int a; const int a;
const unsigned int b; const unsigned int b;
}; };
U u = {.a = 6}; extern const U u = {.a = 6};
// CHECK-DAG: 4:c:@u // CHECK-DAG: 4:c:@u
// No USR can be generated for this. // No USR can be generated for this.

View File

@ -64,7 +64,7 @@ void MapExtDefNamesConsumer::handleDecl(const Decl *D) {
if (const Stmt *Body = FD->getBody()) if (const Stmt *Body = FD->getBody())
addIfInMain(FD, Body->getBeginLoc()); addIfInMain(FD, Body->getBeginLoc());
} else if (const auto *VD = dyn_cast<VarDecl>(D)) { } else if (const auto *VD = dyn_cast<VarDecl>(D)) {
if (cross_tu::containsConst(VD, Ctx) && VD->hasInit()) if (cross_tu::shouldImport(VD, Ctx) && VD->hasInit())
if (const Expr *Init = VD->getInit()) if (const Expr *Init = VD->getInit())
addIfInMain(VD, Init->getBeginLoc()); addIfInMain(VD, Init->getBeginLoc());
} }