[PATCH] D146727: [clangd] Use expansion location for missing include diagnostics.

Viktoriia Bakalova via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Mon Mar 27 05:06:24 PDT 2023


VitaNuo marked an inline comment as done.
VitaNuo added a comment.

Thanks for the comments!



================
Comment at: clang-tools-extra/clangd/IncludeCleaner.cpp:382
 
-        auto &Tokens = AST.getTokens();
-        auto SpelledForExpanded =
-            Tokens.spelledForExpanded(Tokens.expandedTokens(Ref.RefLocation));
-        if (!SpelledForExpanded)
+        auto ExpansionLoc = SM.getExpansionLoc(Ref.RefLocation);
+        const auto *Token = AST.getTokens().spelledTokenAt(ExpansionLoc);
----------------
kadircet wrote:
> can you actually get the spelling location first and use expansion location only when it isn't inside the main file?
> that way we get to preserve the behaviour for macro arguments, which warrants a test like:
> ```
> #define FOO(X) const X x
> 
> FOO([[Foo]]); // we should have a missing include for symbol Foo here
> ```
> 
> and can we have a comment about reasons and implications, e.g. something like:
> ```
> Spelling locations can point into preamble section at times. We don't want to emit diagnostics there as the offsets might be off when preamble is stale.
> In such cases we fallback to expansion locations, as they're always in the main file. This means we fail to attach diagnostics to spelling of symbol names inside macro bodies.
> // FIXME: Use presumed locations to make sure we can correctly generate diagnostics even in such cases.
> ```
Sam suggested a magic solution for this, which is `SM.getFileLoc(Ref.RefLocation)`. Its documentation says:

```
/// Given \p Loc, if it is a macro location return the expansion
/// location or the spelling location, depending on if it comes from a
/// macro argument or not.
```

Sounds like what we need, right?


================
Comment at: clang-tools-extra/include-cleaner/lib/Analysis.cpp:36
     walkAST(*Root, [&](SourceLocation Loc, NamedDecl &ND, RefType RT) {
-      if (!SM.isWrittenInMainFile(SM.getSpellingLoc(Loc)))
+      if (!SM.isWrittenInMainFile(SM.getSpellingLoc(Loc)) &&
+          SM.getDecomposedLoc(SM.getSpellingLoc(Loc)).first !=
----------------
kadircet wrote:
> you can directly use expansion location instead of checking both and mentioning preamble file id here, eg: `!SM.isWrittenInMainFile(SM.getExpansionLoc(Loc))`
This actually leads to both `BAR` and `Foo` in `#define BAR(x) Foo *x` in `foo.h` being recognized as missing and attaches 2 diagnostics to `[[BAR]](b)` in the main file. AFAIU, this is exactly what you're asking me to prevent in the previous comment.




Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D146727



More information about the cfe-commits mailing list