r.stahl updated this revision to Diff 146609.
r.stahl marked an inline comment as done.
r.stahl added a comment.

- added tests
- updated doc and var naming
- addressed review comment


https://reviews.llvm.org/D46421

Files:
  include/clang/CrossTU/CrossTranslationUnit.h
  lib/CrossTU/CrossTranslationUnit.cpp
  lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
  test/Analysis/Inputs/ctu-other.cpp
  test/Analysis/Inputs/externalFnMap.txt
  test/Analysis/ctu-main.cpp
  test/Analysis/func-mapping-test.cpp

Index: test/Analysis/func-mapping-test.cpp
===================================================================
--- test/Analysis/func-mapping-test.cpp
+++ test/Analysis/func-mapping-test.cpp
@@ -3,5 +3,16 @@
 int f(int) {
   return 0;
 }
+// CHECK-DAG: c:@F@f#I#
 
-// CHECK: c:@F@f#I#
+int x = 5;
+// CHECK-DAG: c:@x
+
+struct S {
+  int a;
+};
+S s = {.a = 2};
+// CHECK-DAG: c:@s
+
+int arr[5] = { 0, 1 };
+// CHECK-DAG: c:@arr
Index: test/Analysis/ctu-main.cpp
===================================================================
--- test/Analysis/ctu-main.cpp
+++ test/Analysis/ctu-main.cpp
@@ -42,6 +42,15 @@
 
 int fun_using_anon_struct(int);
 
+extern const int extInt;
+namespace intns {
+extern const int extInt;
+}
+struct S {
+  int a;
+};
+extern const S extS;
+
 int main() {
   clang_analyzer_eval(f(3) == 2); // expected-warning{{TRUE}}
   clang_analyzer_eval(f(4) == 3); // expected-warning{{TRUE}}
@@ -58,4 +67,8 @@
 
   clang_analyzer_eval(chns::chf1(4) == 12); // expected-warning{{TRUE}}
   clang_analyzer_eval(fun_using_anon_struct(8) == 8); // expected-warning{{TRUE}}
+
+  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}}
 }
Index: test/Analysis/Inputs/externalFnMap.txt
===================================================================
--- test/Analysis/Inputs/externalFnMap.txt
+++ test/Analysis/Inputs/externalFnMap.txt
@@ -12,3 +12,6 @@
 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:@extInt ctu-other.cpp.ast
+c:@N@intns@extInt ctu-other.cpp.ast
+c:@extS ctu-other.cpp.ast
Index: test/Analysis/Inputs/ctu-other.cpp
===================================================================
--- test/Analysis/Inputs/ctu-other.cpp
+++ test/Analysis/Inputs/ctu-other.cpp
@@ -68,3 +68,12 @@
 
 typedef struct { int n; } Anonymous;
 int fun_using_anon_struct(int n) { Anonymous anon; anon.n = n; return anon.n; }
+
+extern const int extInt = 2;
+namespace intns {
+extern const int extInt = 3;
+}
+struct S {
+  int a;
+};
+extern const S extS = {.a = 4};
Index: lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
===================================================================
--- lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
+++ lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
@@ -346,6 +346,27 @@
     return true;
   }
 
+  bool VisitVarDecl(VarDecl *VD) {
+    if (!Opts->naiveCTUEnabled())
+      return true;
+
+    if (!VD->hasExternalStorage() ||
+        VD->getAnyInitializer() != nullptr)
+      return true;
+
+    llvm::Expected<const VarDecl *> CTUDeclOrError =
+      CTU.getCrossTUDefinition(VD, Opts->getCTUDir(), Opts->getCTUIndexName());
+
+    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"))
Index: lib/CrossTU/CrossTranslationUnit.cpp
===================================================================
--- lib/CrossTU/CrossTranslationUnit.cpp
+++ lib/CrossTU/CrossTranslationUnit.cpp
@@ -87,14 +87,14 @@
     const size_t Pos = Line.find(" ");
     if (Pos > 0 && Pos != std::string::npos) {
       StringRef LineRef{Line};
-      StringRef FunctionLookupName = LineRef.substr(0, Pos);
-      if (Result.count(FunctionLookupName))
+      StringRef LookupName = LineRef.substr(0, Pos);
+      if (Result.count(LookupName))
         return llvm::make_error<IndexError>(
             index_error_code::multiple_definitions, IndexPath.str(), LineNo);
       StringRef FileName = LineRef.substr(Pos + 1);
       SmallString<256> FilePath = CrossTUDir;
       llvm::sys::path::append(FilePath, FileName);
-      Result[FunctionLookupName] = FilePath.str().str();
+      Result[LookupName] = FilePath.str().str();
     } else
       return llvm::make_error<IndexError>(
           index_error_code::invalid_index_format, IndexPath.str(), LineNo);
@@ -111,52 +111,65 @@
   return Result.str();
 }
 
+bool HasDefinition(const FunctionDecl *D, const FunctionDecl *&DefD) {
+  return D->hasBody(DefD);
+}
+bool HasDefinition(const VarDecl *D, const VarDecl *&DefD) {
+  return D->getAnyInitializer(DefD) != nullptr;
+}
+template <typename T> bool HasDefinition(const T *D) {
+  const T *Unused;
+  return HasDefinition(D, Unused);
+}
+
 CrossTranslationUnitContext::CrossTranslationUnitContext(CompilerInstance &CI)
     : CI(CI), Context(CI.getASTContext()) {}
 
 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 LookupFnName) {
   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, LookupFnName))
+        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 || !HasDefinition(ND, ResultDecl))
       continue;
     if (getLookupName(ResultDecl) != LookupFnName)
       continue;
     return ResultDecl;
   }
   return nullptr;
 }
 
-llvm::Expected<const FunctionDecl *>
-CrossTranslationUnitContext::getCrossTUDefinition(const FunctionDecl *FD,
-                                                  StringRef CrossTUDir,
-                                                  StringRef IndexName) {
-  assert(!FD->hasBody() && "FD has a definition in current translation unit!");
-  const std::string LookupFnName = getLookupName(FD);
-  if (LookupFnName.empty())
+template <typename T>
+llvm::Expected<const T *> CrossTranslationUnitContext::getCrossTUDefinitionImpl(
+    const T *D, StringRef CrossTUDir, StringRef IndexName) {
+  assert(!HasDefinition(D) &&
+         "D has a definition in current translation unit!");
+  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);
+      loadExternalAST(LookupName, CrossTUDir, IndexName);
   if (!ASTUnitOrError)
     return ASTUnitOrError.takeError();
   ASTUnit *Unit = *ASTUnitOrError;
@@ -167,12 +180,25 @@
          &Unit->getASTContext().getSourceManager().getFileManager());
 
   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) {
+  return getCrossTUDefinitionImpl(FD, CrossTUDir, IndexName);
+}
+
+llvm::Expected<const VarDecl *>
+CrossTranslationUnitContext::getCrossTUDefinition(const VarDecl *VD,
+                                                  StringRef CrossTUDir,
+                                                  StringRef IndexName) {
+  return getCrossTUDefinitionImpl(VD, CrossTUDir, IndexName);
+}
+
 void CrossTranslationUnitContext::emitCrossTUDiagnostics(const IndexError &IE) {
   switch (IE.getCode()) {
   case index_error_code::missing_index_file:
@@ -194,29 +220,29 @@
 
 llvm::Expected<ASTUnit *> CrossTranslationUnitContext::loadExternalAST(
     StringRef LookupName, StringRef CrossTUDir, StringRef IndexName) {
-  // 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 contain 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;
       else
         llvm::sys::path::append(IndexFile, IndexName);
       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())
       return llvm::make_error<IndexError>(index_error_code::missing_definition);
     StringRef ASTFileName = It->second;
     auto ASTCacheEntry = FileASTUnitMap.find(ASTFileName);
@@ -236,21 +262,34 @@
     } else {
       Unit = ASTCacheEntry->second.get();
     }
-    FunctionASTUnitMap[LookupName] = Unit;
+    NameASTUnitMap[LookupName] = Unit;
   } else {
-    Unit = FnUnitCacheEntry->second;
+    Unit = NameUnitCacheEntry->second;
   }
   return Unit;
 }
 
+template <typename T>
+llvm::Expected<const T *>
+CrossTranslationUnitContext::importDefinitionImpl(const T *D) {
+  ASTImporter &Importer = getOrCreateASTImporter(D->getASTContext());
+  auto *ToDecl = dyn_cast_or_null<T>(Importer.Import(const_cast<T *>(D)));
+  if (!ToDecl)
+    return llvm::make_error<IndexError>(index_error_code::failed_import);
+  assert(HasDefinition(ToDecl));
+  assert(HasDefinition(D) &&
+         "Decls already imported should have a definition.");
+  return ToDecl;
+}
+
 llvm::Expected<const FunctionDecl *>
 CrossTranslationUnitContext::importDefinition(const FunctionDecl *FD) {
-  ASTImporter &Importer = getOrCreateASTImporter(FD->getASTContext());
-  auto *ToDecl =
-      cast<FunctionDecl>(Importer.Import(const_cast<FunctionDecl *>(FD)));
-  assert(ToDecl->hasBody());
-  assert(FD->hasBody() && "Functions already imported should have body.");
-  return ToDecl;
+  return importDefinitionImpl(FD);
+}
+
+llvm::Expected<const VarDecl *>
+CrossTranslationUnitContext::importDefinition(const VarDecl *VD) {
+  return importDefinitionImpl(VD);
 }
 
 ASTImporter &
Index: include/clang/CrossTU/CrossTranslationUnit.h
===================================================================
--- include/clang/CrossTU/CrossTranslationUnit.h
+++ include/clang/CrossTU/CrossTranslationUnit.h
@@ -28,6 +28,7 @@
 class ASTUnit;
 class DeclContext;
 class FunctionDecl;
+class VarDecl;
 class NamedDecl;
 class TranslationUnitDecl;
 
@@ -62,7 +63,7 @@
   int LineNo;
 };
 
-/// This function parses an index file that determines which
+/// \brief This function parses an index file that determines which
 ///        translation unit contains which definition.
 ///
 /// The index file format is the following:
@@ -75,31 +76,31 @@
 
 std::string createCrossTUIndexString(const llvm::StringMap<std::string> &Index);
 
-/// This class is used for tools that requires cross translation
+/// \brief This class is used for tools that requires cross translation
 ///        unit capability.
 ///
-/// This class can load function definitions from external AST files.
+/// This class can load definitions from external AST files.
 /// The loaded definition will be merged back to the original AST using the
 /// AST Importer.
 /// In order to use this class, an index file is required that describes
-/// the locations of the AST files for each function definition.
+/// the locations of the AST files for each definition.
 ///
 /// Note that this class also implements caching.
 class CrossTranslationUnitContext {
 public:
   CrossTranslationUnitContext(CompilerInstance &CI);
   ~CrossTranslationUnitContext();
 
-  /// This function loads a function definition from an external AST
-  ///        file and merge it into the original AST.
+  /// \brief 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
-  /// the current translation unit. A function definition with the same
+  /// This method should only be used on functions that have no definitions or
+  //  variables that have no initializer in
+  /// the current translation unit. 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 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
@@ -109,44 +110,54 @@
   llvm::Expected<const FunctionDecl *>
   getCrossTUDefinition(const FunctionDecl *FD, StringRef CrossTUDir,
                        StringRef IndexName);
+  llvm::Expected<const VarDecl *>
+  getCrossTUDefinition(const VarDecl *VD, StringRef CrossTUDir,
+                       StringRef IndexName);
 
-  /// This function loads a function definition from an external AST
-  ///        file.
+  /// \brief 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 an ASTUnit that contains the definition of the looked up
-  /// function.
+  /// name.
   ///
   /// Note that the AST files should also be in the \p CrossTUDir.
   llvm::Expected<ASTUnit *> loadExternalAST(StringRef LookupName,
                                             StringRef CrossTUDir,
                                             StringRef IndexName);
 
-  /// This function merges a definition from a separate AST Unit into
+  /// \brief This function merges a definition from a separate AST Unit into
   ///        the current one which was created by the compiler instance that
   ///        was passed to the constructor.
   ///
   /// \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.
+  /// \brief Get a name to identify a named decl.
   static std::string getLookupName(const NamedDecl *ND);
 
-  /// Emit diagnostics for the user for potential configuration errors.
+  /// \brief Emit diagnostics for the user for potential configuration errors.
   void emitCrossTUDiagnostics(const IndexError &IE);
 
 private:
   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);
+  template <typename T>
+  const T *findDefInDeclContext(const DeclContext *DC,
+                                StringRef LookupFnName);
+  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;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to