[PATCH] D70512: [clangd] Rethink how SelectionTree deals with macros and #includes.

Sam McCall via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Mon Nov 25 23:57:33 PST 2019


sammccall planned changes to this revision.
sammccall added a comment.

No, this patch is busted, and the tests were too simple go catch it.

The issue is that with no exclusivity check, given `{{{ MACRO }}}` all the enclosing blocks get to count themselves selected.

We need an exclusivity check on the expanded token stream first. This will yield a sequence of slices of tokens not yet claimed. Then each slice gets partitioned by FileID, each partition gets mapped to spelled tokens and checked as in this patch.

I suspect the exclusivity/claiming at the spelled token level is no longer needed.



================
Comment at: clang-tools-extra/clangd/Selection.cpp:49
+    Result = New;
+  else if (Result != New)
+    Result = SelectionTree::Partial;
----------------
hokein wrote:
> I might be missing something, I don't understand why we set Partial if `Result != New`.
Added a brief comment and an assertion.
Intuitive explanation: Consider `Complete` = black, `Unselected` = white, `Partial` = grey.
White + White -> white, Black + Black -> black, every other mixture is grey.

(But honestly I wrote up the state transition table first and then extracted the logic by staring at it)


================
Comment at: clang-tools-extra/clangd/Selection.cpp:446
+    // Consider the macro expansion FLAG(x) -> int x = 0;
+    // Neither S.getBegin() nor S.getEnd() are arg expansions, but x is.
+    // The selection FLAG([[x]]) must partially select the VarDecl.
----------------
hokein wrote:
> what's S for this case?
S is the function parameter, the implication is that it's the range of the vardecl in the example. Expanded the comment a bit.


================
Comment at: clang-tools-extra/clangd/Selection.cpp:496
+          // Check if the macro name is selected, don't claim it exclusively.
+          auto Expansion = SM.getDecomposedExpansionLoc(S.getBegin());
+          if (Expansion.first == SelFile)
----------------
hokein wrote:
> not sure what's the rational behavior, but I think for the following case, we just have the TUDecl in the selection tree, maybe use the whole macro range?
> 
> ```
> #define M() 123
> 
> int d = M(^); // now we only have the TUDecl in the selection tree.
> ```
This is definitely better, but isn't trivial to do, and isn't a very important case.
Added a FIXME rather than clutter/delay this patch with it.


================
Comment at: clang/lib/Tooling/Syntax/Tokens.cpp:125
+    return {};
+  const Token *Begin =
+      llvm::partition_point(expandedTokens(), [&](const syntax::Token &T) {
----------------
hokein wrote:
> nit: for code readability, I'd use `llvm::ArrayRef<syntax::Token>::iterator` type here.
I think that hurts readability on two counts:
 - it obscures the actual type: a pointer is concrete and familiar, so it's easier to realize that e.g. `>` is well-defined here
 - it makes it harder to understand `return {Begin, End}` which relies on the fact that the actual type here is Token*


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D70512





More information about the cfe-commits mailing list