jkorous updated this revision to Diff 196744.
jkorous added a comment.

- clang-format
- comments


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D61103/new/

https://reviews.llvm.org/D61103

Files:
  clang/include/clang/AST/ASTContext.h
  clang/lib/AST/ASTContext.cpp
  clang/lib/Sema/SemaDecl.cpp
  clang/test/Sema/warn-documentation.cpp

Index: clang/test/Sema/warn-documentation.cpp
===================================================================
--- clang/test/Sema/warn-documentation.cpp
+++ clang/test/Sema/warn-documentation.cpp
@@ -760,16 +760,6 @@
 /// \endcode
 int test_verbatim_2();
 
-// FIXME: we give a bad diagnostic here because we throw away non-documentation
-// comments early.
-//
-// expected-warning@+3 {{'\endcode' command does not terminate a verbatim text block}}
-/// \code
-//  foo
-/// \endcode
-int test_verbatim_3();
-
-
 // expected-warning@+1 {{empty paragraph passed to '\brief' command}}
 int test1; ///< \brief\author Aaa
 
Index: clang/lib/Sema/SemaDecl.cpp
===================================================================
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -12380,19 +12380,7 @@
   }
 
   // See if there are any new comments that are not attached to a decl.
-  ArrayRef<RawComment *> Comments = Context.getRawCommentList().getComments();
-  if (!Comments.empty() &&
-      !Comments.back()->isAttached()) {
-    // There is at least one comment that not attached to a decl.
-    // Maybe it should be attached to one of these decls?
-    //
-    // Note that this way we pick up not only comments that precede the
-    // declaration, but also comments that *follow* the declaration -- thanks to
-    // the lookahead in the lexer: we've consumed the semicolon and looked
-    // ahead through comments.
-    for (unsigned i = 0, e = Group.size(); i != e; ++i)
-      Context.getCommentForDecl(Group[i], &PP);
-  }
+  Context.tryToAttachCommentsToDecls(Group, &PP);
 }
 
 /// ActOnParamDeclarator - Called from Parser::ParseFunctionDeclarator()
Index: clang/lib/AST/ASTContext.cpp
===================================================================
--- clang/lib/AST/ASTContext.cpp
+++ clang/lib/AST/ASTContext.cpp
@@ -489,6 +489,140 @@
   return RC;
 }
 
+void ASTContext::tryToAttachCommentsToDecls(ArrayRef<Decl *> Decls,
+                                            const Preprocessor *PP) {
+  // Explicitly not calling ExternalSource->ReadComments() as we're interested
+  // only in comments and decls that were parsed just now.
+  ArrayRef<RawComment *> RawComments = Comments.getComments();
+  if (RawComments.empty())
+    return;
+
+  auto CacheCommentForDecl = [this, PP](const Decl *D, const RawComment *C) {
+    RawCommentAndCacheFlags CacheEntry;
+    CacheEntry.setKind(RawCommentAndCacheFlags::FromDecl);
+    CacheEntry.setRaw(C);
+    CacheEntry.setOriginalDecl(D);
+    RedeclComments[D] = CacheEntry;
+
+    // Always try to parse in order to eventually produce diagnostics.
+    comments::FullComment *FC = C->parse(*this, PP, D);
+    // But cache only if we don't have a comment yet
+    const Decl *Canonical = D->getCanonicalDecl();
+    auto ParsedComment = ParsedComments.find(Canonical);
+    if (ParsedComment != ParsedComments.end())
+      ParsedComment->second = FC;
+  };
+
+  // explicit comment location caching
+  std::unordered_map<RawComment *, std::pair<FileID, unsigned>>
+      DecomposedCommentBegin;
+  std::unordered_map<RawComment *, std::pair<FileID, unsigned>>
+      DecomposedCommentEnd;
+  std::unordered_map<unsigned, std::unordered_map<unsigned, unsigned>>
+      CommentBeginLine;
+
+  // Don't store the result for long - might go dangling.
+  auto GetCachedCommentBegin =
+      [&DecomposedCommentBegin,
+       this](RawComment *RC) -> const std::pair<FileID, unsigned> & {
+    assert(RC);
+    auto BeginIt = DecomposedCommentBegin.find(RC);
+    if (BeginIt != DecomposedCommentBegin.end()) {
+      return BeginIt->second;
+    }
+    DecomposedCommentBegin[RC] =
+        SourceMgr.getDecomposedLoc(RC->getSourceRange().getBegin());
+    return DecomposedCommentBegin[RC];
+  };
+  // Don't store the result for long - might go dangling.
+  auto GetCachedCommentEnd =
+      [&DecomposedCommentEnd,
+       this](RawComment *RC) -> const std::pair<FileID, unsigned> & {
+    assert(RC);
+    auto EndIt = DecomposedCommentEnd.find(RC);
+    if (EndIt != DecomposedCommentEnd.end()) {
+      return EndIt->second;
+    }
+    DecomposedCommentEnd[RC] =
+        SourceMgr.getDecomposedLoc(RC->getSourceRange().getEnd());
+    return DecomposedCommentEnd[RC];
+  };
+  auto GetCachedCommentBeginLine =
+      [&CommentBeginLine,
+       this](const std::pair<FileID, unsigned> &CommentBeginLoc) -> unsigned {
+    auto BeginFileIt =
+        CommentBeginLine.find(CommentBeginLoc.first.getHashValue());
+    if (BeginFileIt != CommentBeginLine.end()) {
+      auto BeginLineIt = BeginFileIt->second.find(CommentBeginLoc.second);
+      if (BeginLineIt != BeginFileIt->second.end()) {
+        return BeginLineIt->second;
+      }
+    }
+    CommentBeginLine[CommentBeginLoc.first.getHashValue()]
+                    [CommentBeginLoc.second] = SourceMgr.getLineNumber(
+                        CommentBeginLoc.first, CommentBeginLoc.second);
+    return CommentBeginLine[CommentBeginLoc.first.getHashValue()]
+                           [CommentBeginLoc.second];
+  };
+
+  for (const Decl *D : Decls) {
+    D = adjustDeclToTemplate(D);
+    if (!CanDeclHaveDocComment(D))
+      continue;
+
+    {
+      auto CIt = RedeclComments.find(D);
+      if (CIt != RedeclComments.end() && CIt->second.getOriginalDecl() == D) {
+        continue;
+      }
+    }
+
+    llvm::Optional<SourceLocation> OptCandidateCommentLoc =
+        getCandidateCommentLocation(SourceMgr, D);
+    if (!OptCandidateCommentLoc)
+      continue;
+
+    const std::pair<FileID, unsigned> DeclLocDecomp =
+        SourceMgr.getDecomposedLoc(OptCandidateCommentLoc.getValue());
+
+    // FIXME: We might optimize by keeping count of unattached comments and
+    // terminating early.
+    for (auto CIt = RawComments.begin(); CIt != RawComments.end(); ++CIt) {
+      RawComment *C = *CIt;
+      if (!C->isDocumentation() && !LangOpts.CommentOpts.ParseAllComments)
+        continue;
+
+      if (C->isAttached())
+        continue;
+
+      if (C->isTrailingComment()) {
+        if (isa<FieldDecl>(D) || isa<EnumConstantDecl>(D) || isa<VarDecl>(D) ||
+            isa<ObjCMethodDecl>(D) || isa<ObjCPropertyDecl>(D)) {
+          const std::pair<FileID, unsigned> &CommentBeginDecomp =
+              GetCachedCommentBegin(C);
+          // Check that Doxygen trailing comment comes after the declaration,
+          // starts on the same line and in the same file as the declaration.
+          if (DeclLocDecomp.first == CommentBeginDecomp.first &&
+              SourceMgr.getLineNumber(DeclLocDecomp.first,
+                                      DeclLocDecomp.second) ==
+                  GetCachedCommentBeginLine(CommentBeginDecomp)) {
+            C->setAttached();
+            CacheCommentForDecl(D, C);
+            break;
+          }
+        }
+      } else {
+        if (IsCommentBeforeDecl(SourceMgr, GetCachedCommentEnd(C),
+                                DeclLocDecomp)) {
+          C->setAttached();
+          CacheCommentForDecl(D, C);
+          break;
+        }
+      }
+    }
+  }
+}
+
 static void addRedeclaredMethods(const ObjCMethodDecl *ObjCMethod,
                    SmallVectorImpl<const NamedDecl *> &Redeclared) {
   const DeclContext *DC = ObjCMethod->getDeclContext();
Index: clang/include/clang/AST/ASTContext.h
===================================================================
--- clang/include/clang/AST/ASTContext.h
+++ clang/include/clang/AST/ASTContext.h
@@ -814,6 +814,14 @@
   getRawCommentForAnyRedecl(const Decl *D,
                             const Decl **OriginalDecl = nullptr) const;
 
+  /// For every comment not attached to any decl check if it should be attached
+  /// to any of \param Decls.
+  ///
+  /// \param PP the Preprocessor used with this TU.  Could be nullptr if
+  /// preprocessor is not available.
+  void tryToAttachCommentsToDecls(ArrayRef<Decl *> Decls,
+                                  const Preprocessor *PP);
+
   /// Return parsed documentation comment attached to a given declaration.
   /// Returns nullptr if no comment is attached.
   ///
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to