[clang-tools-extra] r190950 - Check for #include in extern and namespace blocks.

John Thompson John.Thompson.JTSoftware at gmail.com
Wed Sep 18 11:19:43 PDT 2013


Author: jtsoftware
Date: Wed Sep 18 13:19:43 2013
New Revision: 190950

URL: http://llvm.org/viewvc/llvm-project?rev=190950&view=rev
Log:
Check for #include in extern and namespace blocks.

Added:
    clang-tools-extra/trunk/test/modularize/Inputs/Empty.h
    clang-tools-extra/trunk/test/modularize/Inputs/IncludeInExtern.h
    clang-tools-extra/trunk/test/modularize/Inputs/IncludeInNamespace.h
    clang-tools-extra/trunk/test/modularize/ProblemsExternC.modularize
    clang-tools-extra/trunk/test/modularize/ProblemsNamespace.modularize
Modified:
    clang-tools-extra/trunk/modularize/Modularize.cpp
    clang-tools-extra/trunk/modularize/PreprocessorTracker.cpp
    clang-tools-extra/trunk/modularize/PreprocessorTracker.h

Modified: clang-tools-extra/trunk/modularize/Modularize.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/modularize/Modularize.cpp?rev=190950&r1=190949&r2=190950&view=diff
==============================================================================
--- clang-tools-extra/trunk/modularize/Modularize.cpp (original)
+++ clang-tools-extra/trunk/modularize/Modularize.cpp Wed Sep 18 13:19:43 2013
@@ -75,6 +75,19 @@
 //             ^
 //   Macro defined here.
 //
+// Checks will also be performed for '#include' directives that are
+// nested inside 'extern "C/C++" {}' or 'namespace (name) {}' blocks,
+// and can produce error message like the following:
+//
+// IncludeInExtern.h:2:3
+//   #include "Empty.h"
+//   ^
+// error: Include directive within extern "C" {}.
+// IncludeInExtern.h:1:1
+// extern "C" {
+// ^
+// The "extern "C" {}" block is here.
+//
 // See PreprocessorTracker.cpp for additional details.
 //
 // Future directions:
@@ -84,18 +97,15 @@
 //
 // Some ideas:
 //
-// 1. Check for and warn about "#include" directives inside 'extern "C/C++" {}'
-// and "namespace (name) {}" blocks.
-//
-// 2. Omit duplicate "not always provided" messages
+// 1. Omit duplicate "not always provided" messages
 //
-// 3. Add options to disable any of the checks, in case
+// 2. Add options to disable any of the checks, in case
 // there is some problem with them, or the messages get too verbose.
 //
-// 4. Try to figure out the preprocessor conditional directives that
+// 3. Try to figure out the preprocessor conditional directives that
 // contribute to problems and tie them to the inconsistent definitions.
 //
-// 5. There are some legitimate uses of preprocessor macros that
+// 4. There are some legitimate uses of preprocessor macros that
 // modularize will flag as errors, such as repeatedly #include'ing
 // a file and using interleaving defined/undefined macros
 // to change declarations in the included file.  Is there a way
@@ -103,7 +113,7 @@
 // to ignore.  Otherwise you can just exclude the file, after checking
 // for legitimate errors.
 //
-// 6. What else?
+// 5. What else?
 //
 // General clean-up and refactoring:
 //
@@ -453,8 +463,11 @@ private:
 class CollectEntitiesVisitor
     : public RecursiveASTVisitor<CollectEntitiesVisitor> {
 public:
-  CollectEntitiesVisitor(SourceManager &SM, EntityMap &Entities)
-      : SM(SM), Entities(Entities) {}
+  CollectEntitiesVisitor(SourceManager &SM, EntityMap &Entities,
+                         Preprocessor &PP, PreprocessorTracker &PPTracker,
+                         int &HadErrors)
+      : SM(SM), Entities(Entities), PP(PP), PPTracker(PPTracker),
+        HadErrors(HadErrors) {}
 
   bool TraverseStmt(Stmt *S) { return true; }
   bool TraverseType(QualType T) { return true; }
@@ -478,6 +491,42 @@ public:
   bool TraverseConstructorInitializer(CXXCtorInitializer *Init) { return true; }
   bool TraverseLambdaCapture(LambdaExpr::Capture C) { return true; }
 
+  // Check 'extern "*" {}' block for #include directives.
+  bool VisitLinkageSpecDecl(LinkageSpecDecl *D) {
+    // Bail if not a block.
+    if (!D->hasBraces())
+      return true;
+    SourceRange BlockRange = D->getSourceRange();
+    const char *LinkageLabel;
+    switch (D->getLanguage()) {
+    case LinkageSpecDecl::lang_c:
+      LinkageLabel = "extern \"C\" {}";
+      break;
+    case LinkageSpecDecl::lang_cxx:
+      LinkageLabel = "extern \"C++\" {}";
+      break;
+    default:
+      LinkageLabel = "extern \"\" {}";
+    }
+    if (!PPTracker.checkForIncludesInBlock(PP, BlockRange, LinkageLabel,
+                                           errs()))
+      HadErrors = 1;
+    return true;
+  }
+
+  // Check 'namespace (name) {}' block for #include directives.
+  bool VisitNamespaceDecl(const NamespaceDecl *D) {
+    SourceRange BlockRange = D->getSourceRange();
+    std::string Label("namespace ");
+    Label += D->getName();
+    Label += " {}";
+    if (!PPTracker.checkForIncludesInBlock(PP, BlockRange, Label.c_str(),
+                                           errs()))
+      HadErrors = 1;
+    return true;
+  }
+
+  // Collect definition entities.
   bool VisitNamedDecl(NamedDecl *ND) {
     // We only care about file-context variables.
     if (!ND->getDeclContext()->isFileContext())
@@ -517,14 +566,18 @@ public:
 private:
   SourceManager &SM;
   EntityMap &Entities;
+  Preprocessor &PP;
+  PreprocessorTracker &PPTracker;
+  int &HadErrors;
 };
 
 class CollectEntitiesConsumer : public ASTConsumer {
 public:
   CollectEntitiesConsumer(EntityMap &Entities,
                           PreprocessorTracker &preprocessorTracker,
-                          Preprocessor &PP, StringRef InFile)
-      : Entities(Entities), PPTracker(preprocessorTracker), PP(PP) {
+                          Preprocessor &PP, StringRef InFile, int &HadErrors)
+      : Entities(Entities), PPTracker(preprocessorTracker), PP(PP),
+        HadErrors(HadErrors) {
     PPTracker.handlePreprocessorEntry(PP, InFile);
   }
 
@@ -534,7 +587,7 @@ public:
     SourceManager &SM = Ctx.getSourceManager();
 
     // Collect declared entities.
-    CollectEntitiesVisitor(SM, Entities)
+    CollectEntitiesVisitor(SM, Entities, PP, PPTracker, HadErrors)
         .TraverseDecl(Ctx.getTranslationUnitDecl());
 
     // Collect macro definitions.
@@ -556,39 +609,46 @@ private:
   EntityMap &Entities;
   PreprocessorTracker &PPTracker;
   Preprocessor &PP;
+  int &HadErrors;
 };
 
 class CollectEntitiesAction : public SyntaxOnlyAction {
 public:
   CollectEntitiesAction(EntityMap &Entities,
-                        PreprocessorTracker &preprocessorTracker)
-      : Entities(Entities), PPTracker(preprocessorTracker) {}
+                        PreprocessorTracker &preprocessorTracker,
+                        int &HadErrors)
+      : Entities(Entities), PPTracker(preprocessorTracker),
+        HadErrors(HadErrors) {}
 
 protected:
   virtual clang::ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
                                                 StringRef InFile) {
     return new CollectEntitiesConsumer(Entities, PPTracker,
-                                       CI.getPreprocessor(), InFile);
+                                       CI.getPreprocessor(), InFile, HadErrors);
   }
 
 private:
   EntityMap &Entities;
   PreprocessorTracker &PPTracker;
+  int &HadErrors;
 };
 
 class ModularizeFrontendActionFactory : public FrontendActionFactory {
 public:
   ModularizeFrontendActionFactory(EntityMap &Entities,
-                                  PreprocessorTracker &preprocessorTracker)
-      : Entities(Entities), PPTracker(preprocessorTracker) {}
+                                  PreprocessorTracker &preprocessorTracker,
+                                  int &HadErrors)
+      : Entities(Entities), PPTracker(preprocessorTracker),
+        HadErrors(HadErrors) {}
 
   virtual CollectEntitiesAction *create() {
-    return new CollectEntitiesAction(Entities, PPTracker);
+    return new CollectEntitiesAction(Entities, PPTracker, HadErrors);
   }
 
 private:
   EntityMap &Entities;
   PreprocessorTracker &PPTracker;
+  int &HadErrors;
 };
 
 int main(int Argc, const char **Argv) {
@@ -626,8 +686,9 @@ int main(int Argc, const char **Argv) {
   EntityMap Entities;
   ClangTool Tool(*Compilations, Headers);
   Tool.appendArgumentsAdjuster(new AddDependenciesAdjuster(Dependencies));
-  int HadErrors =
-      Tool.run(new ModularizeFrontendActionFactory(Entities, *PPTracker));
+  int HadErrors = 0;
+  HadErrors |= Tool.run(
+      new ModularizeFrontendActionFactory(Entities, *PPTracker, HadErrors));
 
   // Create a place to save duplicate entity locations, separate bins per kind.
   typedef SmallVector<Location, 8> LocationArray;

Modified: clang-tools-extra/trunk/modularize/PreprocessorTracker.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/modularize/PreprocessorTracker.cpp?rev=190950&r1=190949&r2=190950&view=diff
==============================================================================
--- clang-tools-extra/trunk/modularize/PreprocessorTracker.cpp (original)
+++ clang-tools-extra/trunk/modularize/PreprocessorTracker.cpp Wed Sep 18 13:19:43 2013
@@ -7,7 +7,7 @@
 //
 //===--------------------------------------------------------------------===//
 //
-// The Basic Idea
+// The Basic Idea (Macro and Conditional Checking)
 //
 // Basically we install a PPCallbacks-derived object to track preprocessor
 // activity, namely when a header file is entered/exited, when a macro
@@ -49,7 +49,17 @@
 //             ^
 //   Macro defined here.
 //
-// Design and Implementation Details
+// The Basic Idea ('Extern "C/C++" {}' Or 'namespace {}') With Nested
+// '#include' Checking)
+//
+// To check for '#include' directives nested inside 'Extern "C/C++" {}'
+// or 'namespace {}' blocks, we keep track of the '#include' directives
+// while running the preprocessor, and later during a walk of the AST
+// we call a function to check for any '#include' directies inside
+// an 'Extern "C/C++" {}' or 'namespace {}' block, given its source
+// range.
+//
+// Design and Implementation Details (Macro and Conditional Checking)
 //
 // A PreprocessorTrackerImpl class implements the PreprocessorTracker
 // interface. It uses a PreprocessorCallbacks class derived from PPCallbacks
@@ -205,6 +215,22 @@
 // to make clearer the separate reporting phases, I could add an output
 // message marking the phases.
 //
+// Design and Implementation Details ('Extern "C/C++" {}' Or
+// 'namespace {}') With Nested '#include' Checking)
+//
+// We override the InclusionDirective in PPCallbacks to record information
+// about each '#include' directive encountered during preprocessing.
+// We co-opt the PPItemKey class to store the information about each
+// '#include' directive, including the source file name containing the
+// directive, the name of the file being included, and the source line
+// and column of the directive.  We store these object in a vector,
+// after first check to see if an entry already exists.
+//
+// Later, while the AST is being walked for other checks, we provide
+// visit handlers for 'extern "C/C++" {}' and 'namespace (name) {}'
+// blocks, checking to see if any '#include' directives occurred
+// within the blocks, reporting errors if any found.
+//
 // Future Directions
 //
 // We probably should add options to disable any of the checks, in case
@@ -285,7 +311,7 @@ std::string getSourceString(clang::Prepr
   return llvm::StringRef(BeginPtr, Length).trim().str();
 }
 
-// Retrieve source line from file image.
+// Retrieve source line from file image given a location.
 std::string getSourceLine(clang::Preprocessor &PP, clang::SourceLocation Loc) {
   const llvm::MemoryBuffer *MemBuffer =
       PP.getSourceManager().getBuffer(PP.getSourceManager().getFileID(Loc));
@@ -310,6 +336,39 @@ std::string getSourceLine(clang::Preproc
   return llvm::StringRef(BeginPtr, Length).str();
 }
 
+// Retrieve source line from file image given a file ID and line number.
+std::string getSourceLine(clang::Preprocessor &PP, clang::FileID FileID,
+                          int Line) {
+  const llvm::MemoryBuffer *MemBuffer = PP.getSourceManager().getBuffer(FileID);
+  const char *Buffer = MemBuffer->getBufferStart();
+  const char *BufferEnd = MemBuffer->getBufferEnd();
+  const char *BeginPtr = Buffer;
+  const char *EndPtr = BufferEnd;
+  int LineCounter = 1;
+  if (Line == 1)
+    BeginPtr = Buffer;
+  else {
+    while (Buffer < BufferEnd) {
+      if (*Buffer == '\n') {
+        if (++LineCounter == Line) {
+          BeginPtr = Buffer++ + 1;
+          break;
+        }
+      }
+      Buffer++;
+    }
+  }
+  while (Buffer < BufferEnd) {
+    if (*Buffer == '\n') {
+      EndPtr = Buffer;
+      break;
+    }
+    Buffer++;
+  }
+  size_t Length = EndPtr - BeginPtr;
+  return llvm::StringRef(BeginPtr, Length).str();
+}
+
 // Get the string for the Unexpanded macro instance.
 // The soureRange is expected to end at the last token
 // for the macro instance, which in the case of a function-style
@@ -765,6 +824,14 @@ public:
   ~PreprocessorCallbacks() {}
 
   // Overridden handlers.
+  void InclusionDirective(clang::SourceLocation HashLoc,
+                          const clang::Token &IncludeTok,
+                          llvm::StringRef FileName, bool IsAngled,
+                          clang::CharSourceRange FilenameRange,
+                          const clang::FileEntry *File,
+                          llvm::StringRef SearchPath,
+                          llvm::StringRef RelativePath,
+                          const clang::Module *Imported);
   void FileChanged(clang::SourceLocation Loc,
                    clang::PPCallbacks::FileChangeReason Reason,
                    clang::SrcMgr::CharacteristicKind FileType,
@@ -821,6 +888,70 @@ public:
   // Handle exiting a preprocessing session.
   void handlePreprocessorExit() { HeaderStack.clear(); }
 
+  // Handle include directive.
+  // This function is called every time an include directive is seen by the
+  // preprocessor, for the purpose of later checking for 'extern "" {}' or
+  // "namespace {}" blocks containing #include directives.
+  void handleIncludeDirective(llvm::StringRef DirectivePath, int DirectiveLine,
+                              int DirectiveColumn, llvm::StringRef TargetPath) {
+    HeaderHandle CurrentHeaderHandle = findHeaderHandle(DirectivePath);
+    StringHandle IncludeHeaderHandle = addString(TargetPath);
+    for (std::vector<PPItemKey>::const_iterator I = IncludeDirectives.begin(),
+                                                E = IncludeDirectives.end();
+         I != E; ++I) {
+      // If we already have an entry for this directive, return now.
+      if ((I->File == CurrentHeaderHandle) && (I->Line == DirectiveLine))
+        return;
+    }
+    PPItemKey IncludeDirectiveItem(IncludeHeaderHandle, CurrentHeaderHandle,
+                                   DirectiveLine, DirectiveColumn);
+    IncludeDirectives.push_back(IncludeDirectiveItem);
+  }
+
+  // Check for include directives within the given source line range.
+  // Report errors if any found.  Returns true if no include directives
+  // found in block.
+  bool checkForIncludesInBlock(clang::Preprocessor &PP,
+                               clang::SourceRange BlockSourceRange,
+                               const char *BlockIdentifierMessage,
+                               llvm::raw_ostream &OS) {
+    clang::SourceLocation BlockStartLoc = BlockSourceRange.getBegin();
+    clang::SourceLocation BlockEndLoc = BlockSourceRange.getEnd();
+    // Use block location to get FileID of both the include directive
+    // and block statement.
+    clang::FileID FileID = PP.getSourceManager().getFileID(BlockStartLoc);
+    std::string SourcePath = getSourceLocationFile(PP, BlockStartLoc);
+    HeaderHandle SourceHandle = findHeaderHandle(SourcePath);
+    int BlockStartLine, BlockStartColumn, BlockEndLine, BlockEndColumn;
+    bool returnValue = true;
+    getSourceLocationLineAndColumn(PP, BlockStartLoc, BlockStartLine,
+                                   BlockStartColumn);
+    getSourceLocationLineAndColumn(PP, BlockEndLoc, BlockEndLine,
+                                   BlockEndColumn);
+    for (std::vector<PPItemKey>::const_iterator I = IncludeDirectives.begin(),
+                                                E = IncludeDirectives.end();
+         I != E; ++I) {
+      // If we find an entry within the block, report an error.
+      if ((I->File == SourceHandle) && (I->Line >= BlockStartLine) &&
+          (I->Line < BlockEndLine)) {
+        returnValue = false;
+        OS << SourcePath << ":" << I->Line << ":" << I->Column << "\n";
+        OS << getSourceLine(PP, FileID, I->Line) << "\n";
+        if (I->Column > 0)
+          OS << std::string(I->Column - 1, ' ') << "^\n";
+        OS << "error: Include directive within " << BlockIdentifierMessage
+           << ".\n";
+        OS << SourcePath << ":" << BlockStartLine << ":" << BlockStartColumn
+           << "\n";
+        OS << getSourceLine(PP, BlockStartLoc) << "\n";
+        if (BlockStartColumn > 0)
+          OS << std::string(BlockStartColumn - 1, ' ') << "^\n";
+        OS << "The \"" << BlockIdentifierMessage << "\" block is here.\n";
+      }
+    }
+    return returnValue;
+  }
+
   // Handle entering a header source file.
   void handleHeaderEntry(clang::Preprocessor &PP, llvm::StringRef HeaderPath) {
     // Ignore <built-in> and <command-line> to reduce message clutter.
@@ -1176,6 +1307,7 @@ private:
   std::vector<HeaderInclusionPath> InclusionPaths;
   InclusionPathHandle CurrentInclusionPathHandle;
   llvm::SmallSet<HeaderHandle, 128> HeadersInThisCompile;
+  std::vector<PPItemKey> IncludeDirectives;
   MacroExpansionMap MacroExpansions;
   ConditionalExpansionMap ConditionalExpansions;
   bool InNestedHeader;
@@ -1193,6 +1325,20 @@ PreprocessorTracker *PreprocessorTracker
 
 // Preprocessor callbacks for modularize.
 
+// Handle include directive.
+void PreprocessorCallbacks::InclusionDirective(
+    clang::SourceLocation HashLoc, const clang::Token &IncludeTok,
+    llvm::StringRef FileName, bool IsAngled,
+    clang::CharSourceRange FilenameRange, const clang::FileEntry *File,
+    llvm::StringRef SearchPath, llvm::StringRef RelativePath,
+    const clang::Module *Imported) {
+  int DirectiveLine, DirectiveColumn;
+  std::string HeaderPath = getSourceLocationFile(PP, HashLoc);
+  getSourceLocationLineAndColumn(PP, HashLoc, DirectiveLine, DirectiveColumn);
+  PPTracker.handleIncludeDirective(HeaderPath, DirectiveLine, DirectiveColumn,
+                                   FileName);
+}
+
 // Handle file entry/exit.
 void PreprocessorCallbacks::FileChanged(
     clang::SourceLocation Loc, clang::PPCallbacks::FileChangeReason Reason,

Modified: clang-tools-extra/trunk/modularize/PreprocessorTracker.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/modularize/PreprocessorTracker.h?rev=190950&r1=190949&r2=190950&view=diff
==============================================================================
--- clang-tools-extra/trunk/modularize/PreprocessorTracker.h (original)
+++ clang-tools-extra/trunk/modularize/PreprocessorTracker.h Wed Sep 18 13:19:43 2013
@@ -52,6 +52,22 @@ public:
   // object is destroyed.)
   virtual void handlePreprocessorExit() = 0;
 
+  // Handle include directive.
+  // This function is called every time an include directive is seen by the
+  // preprocessor, for the purpose of later checking for 'extern "" {}' or
+  // "namespace {}" blocks containing #include directives.
+  virtual void handleIncludeDirective(llvm::StringRef DirectivePath,
+                                      int DirectiveLine, int DirectiveColumn,
+                                      llvm::StringRef TargetPath) = 0;
+
+  // Check for include directives within the given source line range.
+  // Report errors if any found.  Returns true if no include directives
+  // found in block.
+  virtual bool checkForIncludesInBlock(clang::Preprocessor &PP,
+                                       clang::SourceRange BlockSourceRange,
+                                       const char *BlockIdentifierMessage,
+                                       llvm::raw_ostream &OS) = 0;
+
   // Report on inconsistent macro instances.
   // Returns true if any mismatches.
   virtual bool reportInconsistentMacros(llvm::raw_ostream &OS) = 0;

Added: clang-tools-extra/trunk/test/modularize/Inputs/Empty.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/modularize/Inputs/Empty.h?rev=190950&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/modularize/Inputs/Empty.h (added)
+++ clang-tools-extra/trunk/test/modularize/Inputs/Empty.h Wed Sep 18 13:19:43 2013
@@ -0,0 +1 @@
+// Empty header for testing #include directives in blocks.

Added: clang-tools-extra/trunk/test/modularize/Inputs/IncludeInExtern.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/modularize/Inputs/IncludeInExtern.h?rev=190950&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/modularize/Inputs/IncludeInExtern.h (added)
+++ clang-tools-extra/trunk/test/modularize/Inputs/IncludeInExtern.h Wed Sep 18 13:19:43 2013
@@ -0,0 +1,3 @@
+extern "C" {
+  #include "Empty.h"
+}

Added: clang-tools-extra/trunk/test/modularize/Inputs/IncludeInNamespace.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/modularize/Inputs/IncludeInNamespace.h?rev=190950&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/modularize/Inputs/IncludeInNamespace.h (added)
+++ clang-tools-extra/trunk/test/modularize/Inputs/IncludeInNamespace.h Wed Sep 18 13:19:43 2013
@@ -0,0 +1,3 @@
+namespace MyNamespace {
+  #include "Empty.h"
+}

Added: clang-tools-extra/trunk/test/modularize/ProblemsExternC.modularize
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/modularize/ProblemsExternC.modularize?rev=190950&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/modularize/ProblemsExternC.modularize (added)
+++ clang-tools-extra/trunk/test/modularize/ProblemsExternC.modularize Wed Sep 18 13:19:43 2013
@@ -0,0 +1,12 @@
+# RUN: not modularize %s -x c++ 2>&1 | FileCheck %s
+
+Inputs/IncludeInExtern.h
+
+# CHECK: {{.*}}{{[/\\]}}Inputs{{[/\\]}}IncludeInExtern.h:2:3
+# CHECK-NEXT:   #include "Empty.h"
+# CHECK-NEXT:   ^
+# CHECK-NEXT: error: Include directive within extern "C" {}.
+# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}IncludeInExtern.h:1:1
+# CHECK-NEXT: extern "C" {
+# CHECK-NEXT: ^
+# CHECK-NEXT: The "extern "C" {}" block is here.

Added: clang-tools-extra/trunk/test/modularize/ProblemsNamespace.modularize
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/modularize/ProblemsNamespace.modularize?rev=190950&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/modularize/ProblemsNamespace.modularize (added)
+++ clang-tools-extra/trunk/test/modularize/ProblemsNamespace.modularize Wed Sep 18 13:19:43 2013
@@ -0,0 +1,12 @@
+# RUN: not modularize %s -x c++ 2>&1 | FileCheck %s
+
+Inputs/IncludeInNamespace.h
+
+# CHECK: {{.*}}{{[/\\]}}Inputs{{[/\\]}}IncludeInNamespace.h:2:3
+# CHECK-NEXT:   #include "Empty.h"
+# CHECK-NEXT:   ^
+# CHECK-NEXT: error: Include directive within namespace MyNamespace {}.
+# CHECK-NEXT: {{.*}}{{[/\\]}}Inputs{{[/\\]}}IncludeInNamespace.h:1:1
+# CHECK-NEXT: namespace MyNamespace {
+# CHECK-NEXT: ^
+# CHECK-NEXT: The "namespace MyNamespace {}" block is here.





More information about the cfe-commits mailing list