This is an archive of the discontinued LLVM Phabricator instance.

[clangd] #include statements support for Open definition
ClosedPublic

Authored by Nebiroth on Oct 6 2017, 11:11 AM.

Event Timeline

There are a very large number of changes, so older changes are hidden. Show Older Changes
ilya-biryukov added inline comments.Oct 9 2017, 5:25 AM
clangd/ClangdUnit.cpp
151

Please use our descriptive Path typedef.

unittests/clangd/ClangdTests.cpp
765

Some includes may come outside of preamble, I would expect current implementation to fail for this case:

#include <vector> // <-- works here 
// preamble ends here
int main() {

  #include "my_include.h" // <-- does not work here
}
Nebiroth marked 21 inline comments as done.Oct 16 2017, 1:51 PM
Nebiroth added inline comments.
clangd/ClangdUnit.cpp
139

If I were to use InclusionDirective , how would that callback be called automatically? As far as I know, it wouldn't be called automatically for every file that gets indexed the same way AfterExecute would be.

Nebiroth marked an inline comment as done.Oct 16 2017, 1:56 PM
ilya-biryukov added inline comments.Oct 23 2017, 5:22 AM
clangd/ClangdUnit.cpp
139

It will be called for each #include directive that Preprocessor encountered while building the preamble.
A separate instance of CppFilePreambleCallbacks is created every time we build a preamble for file.

Does that answer your question?

Nebiroth updated this revision to Diff 120482.Oct 26 2017, 1:58 PM
Nebiroth edited edge metadata.
  • Now overriding InclusionDirective as a callback to get proper includes information.
  • Fixed tests.
Nebiroth updated this revision to Diff 120485.EditedOct 26 2017, 2:00 PM
  • Fixed adding incorrect test file.

This revision requires modifications to clang which can be reviewed on revision D39375.

I'm not sure it's better to use the InclusionDirective callback for this. We need to get the includes in two places: in the preamble and non-preamble. In the preamble we use the callback, have to store some temporary stuff because we don't have a SourceManager in InclusionDirective, then in finish we use the SourceManager to convert everything. In the non-preamble, we cannot use the callback so we use the SourceManager to go through the includes. Therefore, we have to maintain two different ways of getting the inclusion map. Without using the InclusionDirective callback, we use the SourceManager in both cases and can use the same code to iterate through inclusions, just on two different SourceManagers at different moments. We also don't need to make another patch to modify the PreambleCallbacks. I also double this is much slower but I think this simplifies the code nicely.
What do you think?

I'm not sure it's better to use the InclusionDirective callback for this. We need to get the includes in two places: in the preamble and non-preamble. In the preamble we use the callback, have to store some temporary stuff because we don't have a SourceManager in InclusionDirective, then in finish we use the SourceManager to convert everything. In the non-preamble, we cannot use the callback so we use the SourceManager to go through the includes. Therefore, we have to maintain two different ways of getting the inclusion map. Without using the InclusionDirective callback, we use the SourceManager in both cases and can use the same code to iterate through inclusions, just on two different SourceManagers at different moments. We also don't need to make another patch to modify the PreambleCallbacks. I also double this is much slower but I think this simplifies the code nicely.
What do you think?

I think we should never iterate through SourceManager, as it's much easier to get wrong than using the callbacks. I agree that all that fiddling with callbacks is unfortunate, but it's well worth the fact that it'd be much easier to tell that the implementation is correct by simply looking at the implementation and not knowing how SourceManager works. PPCallbacks is a much more direct API that was designed to handle our purposes.

Note that we don't need to use SourceManager to find non-preamble includes, we should implement proper PPCallbacks and use them when building the AST.

ilya-biryukov added inline comments.Nov 9 2017, 7:16 AM
clangd/ClangdServer.cpp
368 ↗(On Diff #120485)

This map and two vectors come up quite often in your commit.
Is this a storage for saved includes? Could we define a class that stores this data?

Something like

class IncludeReferenceMap {
  llvm::Optional<PathRef> findIncludeTargetAtLoc(Location Loc);

private:
// maps, vectors, whatever we need go here ....
};

We'd build it using the callbacks, then store it in PreambleData (for PCH include) and ParsedAST (for non-PCH includes). And later query both maps to get the result.

clangd/ClangdUnit.cpp
32

We probably don't need it this include

36

What's the purpose of this class?

147

Please also use PPCallbacks interface instead of the SourceManager (should be possible to hook it up somewhere in ParsedAST::Build).

ilya-biryukov requested changes to this revision.Nov 9 2017, 7:16 AM
This revision now requires changes to proceed.Nov 9 2017, 7:16 AM

I think we should never iterate through SourceManager, as it's much easier to get wrong than using the callbacks. I agree that all that fiddling with callbacks is unfortunate, but it's well worth the fact that it'd be much easier to tell that the implementation is correct by simply looking at the implementation and not knowing how SourceManager works. PPCallbacks is a much more direct API that was designed to handle our purposes.

Note that we don't need to use SourceManager to find non-preamble includes, we should implement proper PPCallbacks and use them when building the AST.

Sounds good!

Nebiroth marked an inline comment as done.Dec 5 2017, 2:16 PM
Nebiroth added inline comments.
clangd/ClangdUnit.cpp
36

We need to be able to use a wrapper class to be able to make a unique_ptr to be sent to PrecompiledPreamble::Build in order to add the list of preprocessor Callbacks.

Nebiroth updated this revision to Diff 125813.Dec 6 2017, 2:15 PM
Nebiroth edited edge metadata.

Using PPCallbacks interface to find non-preamble includes
Created inner class to store vectors in to find locations
Refactored methods to remove some unnecessary parameters
Refactored Unit tests
Merge with most recent master branch + clang

Nebiroth updated this revision to Diff 125814.Dec 6 2017, 2:17 PM

Fixed re-added include

ilya-biryukov added inline comments.Dec 8 2017, 3:30 AM
clangd/ClangdUnit.cpp
36

Could we implement an instance of PPCallbacks that contains CppFilePreambleCallbacks and forwards to that specific method instead?

The reason is that we're not really delegating other methods in this calls(nor should we, the implementation would be too compilcated).
Having a class that contains CppFilePreambleCallbacks &Collector and calling Collector.InclusionDirective seems perfectly fine, though: its purpose is clear and the implementation is easy.

Nebiroth updated this revision to Diff 126429.Dec 11 2017, 12:55 PM
Creating unique_ptr for wrapper class now uses overriden method createPPCallbacks() from PrecompiledPreamble class
Moved wrapper class to inline inside createPPCallbacks()
Wrapper class now uses CppFilePreambleCallbacks as field
malaperle requested changes to this revision.Dec 14 2017, 9:03 PM
malaperle added inline comments.
clangd/ClangdServer.cpp
454 ↗(On Diff #126429)

IncludeReferenceMap & here? See other comment in takeIRM

clangd/ClangdUnit.cpp
32

remove

111

remove

118

These need to be swapped to be in the same order that they are declared below.

120

I don't think we need this if we pass the map by reference (and store it as a reference, see other comment)

127

Remove (see previous comment)

130

remove

147

I tried to simply the methods introduced here:

void AfterExecute(CompilerInstance &CI) override {
  SourceMgr = &CI.getSourceManager();
  for (auto InclusionLoc : TempPreambleIncludeLocations)
    addIncludeLocation(InclusionLoc);
}

void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
                        StringRef FileName, bool IsAngled,
                        CharSourceRange FilenameRange, const FileEntry *File,
                        StringRef SearchPath, StringRef RelativePath,
                        const Module *Imported) override {
  auto SR = FilenameRange.getAsRange();
  if (SR.isInvalid() || !File || File->tryGetRealPathName().empty())
    return;

  if (SourceMgr) {
    addIncludeLocation({SR, File->tryGetRealPathName()});
  } else {
    // When we are processing the inclusion directives inside the preamble,
    // we don't have access to a SourceManager, so we cannot convert
    // SourceRange to Range. This is done instead in AfterExecute when a
    // SourceManager becomes available.
    TempPreambleIncludeLocations.push_back({SR, File->tryGetRealPathName()});
  }
}

void addIncludeLocation(std::pair<SourceRange, std::string> InclusionLoc) {
  // Only inclusion directives in the main file make sense. The user cannot
  // select directives not in the main file.
  if (SourceMgr->getMainFileID() == SourceMgr->getFileID(InclusionLoc.first.getBegin()))
    IRM.insert({getRange(InclusionLoc.first), InclusionLoc.second});
}

Range getRange(SourceRange SR) {
  Position Begin;
  Begin.line = SourceMgr->getSpellingLineNumber(SR.getBegin());
  Begin.character = SourceMgr->getSpellingColumnNumber(SR.getBegin());
  Position End;
  End.line = SourceMgr->getSpellingLineNumber(SR.getEnd());
  End.character = SourceMgr->getSpellingColumnNumber(SR.getEnd());
  return {Begin, End};
}
151

IncludeReferenceMap &IRM;

That way, we can use the same map and pass it multiple times to different "collectors".

169

I think we need a "is main file" check here. In case this is used on a AST with no preamble.

259

I don't think this change was brought back intentionally?

275

IncludeReferenceMap &IRM

306

unnecessary std::move

316

std::move(IRM)

326–327

I think after rebase, all this code in DeclarationLocationsFinder will need to be moved around, probably inside clangd::findDefinitions?

328
for (auto &IncludeLoc : IncludeLocationMap) {
  Range R = IncludeLoc.first;
  if (isSameLine(R.start.line))
    addLocation(URI::fromFile(IncludeLoc.second), R);
}
335

Probably if an include location was found, we don't want to continue and it should early return.

562

I think you can put the construction of SerializedDeclsCollector back to where it was.

648

You can pass just IRM, so there is no need for the getIRM. We'll have eventually to transfer ownership to ParsedAST so maybe std::move(IRM) here?

clangd/ClangdUnit.h
65

With the map being the only field left (see other comments), there is no need for a class I think. Maybe make a handy type alias for this?

using IncludeReferenceMap = std::unordered_map<Range, Path, RangeHash>;
66

findIncludeTargetAtLoc is never used, remove

70

No need to keep this.

71

No need to keep this.

96

We need to keep this copy of IRM alive for subsequent calls to "open definition" for the same ParsedAST. So it is correct to not do a std::move here. However, I think it should be changed to:

IncludeReferenceMap &getIRM()

and also the caller should assign to a reference.

123

this wrongly came back?

unittests/clangd/ClangdTests.cpp
625–626

why is this check removed?

754

Need to test includes outside preamble.

781

I get an "unchecked assertion" here before the Expected is not checked. I was able to replace it with:

auto ExpectedLocations = Server.findDefinitions(FooCpp, P);
ASSERT_TRUE(!!ExpectedLocations);
std::vector<Location> Locations = ExpectedLocations->Value;
787

I get a test failure here.

../tools/clang/tools/extra/unittests/clangd/ClangdTests.cpp(785): Error:       Expected: check
      Which is: "clangd-test/foo."
To be equal to: FooH
      Which is: { '/' (47, 0x2F), 'c' (99, 0x63), 'l' (108, 0x6C), 'a' (97, 0x61), 'n' (110, 0x6E), 'g' (103, 0x67), 'd' (100, 0x64), '-' (45, 0x2D), 't' (116, 0x74), 'e' (101, 0x65), 's' (115, 0x73), 't' (116, 0x74), '/' (47, 0x2F), 'f' (102, 0x66), 'o' (111, 0x6F), 'o' (111, 0x6F), '.' (46, 0x2E), 'h' (104, 0x68) }

Not sure what's wrong. There is an additional front slash and missing ".h" at the end?

796

Similar unchecked problem here, this works (although a bit yucky):

ExpectedLocations = Server.findDefinitions(FooCpp, P3);
ASSERT_TRUE(!!ExpectedLocations);
Locations = ExpectedLocations->Value;
EXPECT_TRUE(!Locations.empty());

// Test invalid include
Position P2 = Position{2, 11};

ExpectedLocations = Server.findDefinitions(FooCpp, P2);
ASSERT_TRUE(!!ExpectedLocations);
Locations = ExpectedLocations->Value;
EXPECT_TRUE(Locations.empty());
This revision now requires changes to proceed.Dec 14 2017, 9:03 PM
Nebiroth updated this revision to Diff 127161.Dec 15 2017, 10:58 AM
Nebiroth marked 27 inline comments as done.

inner class IncludeReferenceMap replaced by one map
fillRangeVector() and findPreambleIncludes() code moved into wrapper class
Open definition now returns an empty Range struct (line, character = 0)
Fixed unit tests
Minor code improvements

ilya-biryukov requested changes to this revision.Dec 18 2017, 2:22 AM
ilya-biryukov added inline comments.
clangd/ClangdServer.cpp
446 ↗(On Diff #127161)

We don't need this Preamble variable, right?

clangd/ClangdUnit.cpp
111

We don't need to derive this class from PPCallbacks, DelegatingPPCallbacks can call any method on it anyway as it knows the exact type. Please remove this inheritance.

117

Instead of passing SourceManager in constructor, maybe add a BeforeExecute(CompilerInstance &CI) method to PreambleCallbacks and set SourceManager when its called.

153

Adding BeforeExecute would allow to get rid of this vector.

204

NIT: replace with return llvm::make_unique<DelegatingPPCallbacks>(*this); and remove the local variable.

275

Let's store IncludeReferenceMap in ParsedAST instead of having it as out parameter.
It allows to properly manage the lifetime of IncludeReferenceMap (logically, it is exactly tied to the AST).

303

Why do we use CppFilePreambleCallbacks here? Factor the code that handles the references into a separate class and use it here:

class IncludeRefsCollector : public PPCallbacks {
public:
  IncludeRefsCollector(IncludeReferenceMap &Refs) : Refs(Refs) {}

   // implementation of PPCallbacks ...

private;
  IncludeReferenceMap &Refs;
};

/// .....
class CppFilePreambleCaallbacks {
public:
// ....

  std::unique_ptr<PPCallbacks> createPPCallbacks() { return llvm::make_unique<IncludeRefsCollector>(this->IRM); }
};

// ....
void ParsedAST::Build() {
  // ....
  // No need to create CppFilePreambleCallbacks here.
  Clang->getPreprocessor().addPPCallbacks(llvm::make_unique<IncludeRefsCollector>(IRM));
  //....
}
327

Use IncludeReferenceMap typedef here.

327

Do we change semantics of getting the file paths here? Maybe leave the code as is?

327

NIT: empty linke at the start of the function

329
  • use a typedef for the map here
  • accept the map by const reference to avoid copies
330

Let's check the the point is in range, not that it's not the same line. So that we don't trigger goto in strange places, like comments:

#include <vector> // this include is very important.  <--- we should not skip to include when editor caret is over a comment
331

If we store IncludeLocationMap in ParsedAST we don't need to change interface of this function.

332

This method does not seem particularly useful. One can construct location like this: Location{Uri, R}, the whole method can be written as DeclarationLocations.push_back(Location{Uri, R}).

clangd/ClangdUnit.h
65

We store a map, but only iterate through it in order. Let's use vector<pair<Range, Path>> instead.

This revision now requires changes to proceed.Dec 18 2017, 2:22 AM
Nebiroth updated this revision to Diff 127386.Dec 18 2017, 10:31 AM
Nebiroth marked 14 inline comments as done.
CppFilePreambleCallbacks no longer extends PPCallbacks
CppFilePreambleCallbacks no longer needs SourceManager parameter
Removed temporary vector TempPreambleIncludeLocations
IncludeReferenceMap in ParsedAST no longer passed by reference
Code handling includes outside of preambles is now separated in IncludeRefsCollector class
Removed addLocation
Changed isSameLine function name and now checks if searched location is in range instead of verifying the line
Removed changes to findDefinitions interface
ilya-biryukov requested changes to this revision.Dec 19 2017, 1:39 AM

Thanks for addressing the comments quickly.
I took another look and added a few more comments.
This moves in the right direction, though, this is really close to landing.

clangd/ClangdServer.cpp
25 ↗(On Diff #127386)

Is this include redundant now? Can we remove it?

430 ↗(On Diff #127386)

Capturing this seems redundant. Remove it?

clangd/ClangdUnit.cpp
87

clang-format please

87

Do we need both checks? Doesn't SourceMgr.isInMainFile handles all the cases?

117

Let's create a new empty map inside this class and have a takeIncludeReferences method (similar to TopLevelDeclIDs and takeTopLevelDeclIDs)

153

We should have SourceMgr at all the proper places now, let's store IncludeReferenceMap directly

276

What reference does this IncludeReferenceMap contain? Includes from the preamble?

326–327

This class handles processing AST and preprocessor, it does not need to get IncludeLocationMap in constructor or store it at all.
Remove IncludeLocationMap from this class and handle getting references from IncludeLocationMap outside this class instead.

clangd/ClangdUnit.h
96

Make it all const?

const IncludeReferenceMap &getIRM() const { return IRM; }

280

This function moved without need and lost a comment.

This revision now requires changes to proceed.Dec 19 2017, 1:39 AM
Nebiroth marked 8 inline comments as done.Dec 19 2017, 2:15 PM
Nebiroth added inline comments.
clangd/ClangdUnit.cpp
87

This check was here to prevent an issue that appeared previously. I don't think this check is needed anymore.

153

The idea was to pass a single map around to fill with every reference instead of having separate maps being merged together.

276

This should contain every reference available for one file.

Nebiroth marked 2 inline comments as done.Dec 19 2017, 3:38 PM
Nebiroth updated this revision to Diff 127617.Dec 19 2017, 3:55 PM
Removed some useless inclusions
Removed superfluous check when inserting data in map
Moved addition to DeclarationLocations in finish() outside of DeclMacrosFinder
Merged with revision 321087 (moved findDefinitions and findDocumentHighlights
ilya-biryukov requested changes to this revision.Dec 20 2017, 10:17 AM

Another round of review

clangd/ClangdUnit.cpp
117

This comment is not addressed yet, but marked as done.

144

Maybe add assert(SourceMgr && "SourceMgr must be set at this point") here?

153

You copy the map for preamble and then append to it in CppFilePreambleCallbacks? That also LG, we should not have many references there anyway.

276

Thanks for clarifying, LG.

280

Don't we already store the map we need in PreambleData? Why do we need an extra IRM parameter?

clangd/ClangdUnit.h
280

Now we have duplicated definitions here. Bad merge?

clangd/CodeComplete.cpp
328 ↗(On Diff #127617)

Accidental change?

807 ↗(On Diff #127617)

Accidental change?

clangd/XRefs.cpp
41

We don't need locations anymore. Remove them.

142

Probably a good place for a comment. Also, maybe rename local var to something easier to understand like IncludeDefinitions

/// Process targets for paths inside #include directive.
std::vector<Location> IncludeTargets;
143

No need to special case empty maps, remove the if altogether.

148

Replace with DeclMacrosFinder->getSearchedLocation() SourceLocationBeg, it makes the code easier to read.

150

why do we need to convert to unsigned? To slience compiler warnings?

153

this should be R.start.charater <= CharNumber && CharNumber <= R.end.character

This revision now requires changes to proceed.Dec 20 2017, 10:17 AM
ilya-biryukov added inline comments.Dec 21 2017, 7:39 AM
clangd/XRefs.cpp
148

Sorry, the comment got messed up. Here's the correct version:

Replace DeclMacrosFinder->getSearchedLocation() with SourceLocationBeg, it makes the code easier to read.

Nebiroth updated this revision to Diff 127900.Dec 21 2017, 9:11 AM
Nebiroth marked 11 inline comments as done.
Minor code cleanup

@ilya-biryukov Hi! I'll be updating William's patches that were in progress. I just have a few comments/question before I send a new update. (I also don't know if I can update this diff or I have to create a new diff on Phabricator... I guess we'll see!!).

clangd/ClangdUnit.cpp
117

As mentioned below, the idea was to have a single map being appended to, without having to merge two separate maps. However, I can change the code so that two separate maps are built and merged if you prefer.

But I'm not so clear if that's what you'd prefer:

You copy the map for preamble and then append to it in CppFilePreambleCallbacks? That also LG, we should not have many references there anyway.

It's not meant to have any copy. The idea was to create a single IncludeReferenceMap in CppFile::deferRebuild, populate it with both preamble and non-preamble include references and std::move it around for later use (stored in ParsedAST).

280

Since the map will be now stored in ParsedAST and the instance doesn't exist yet, we need to keep the IRM parameter. I noticed that it wasn't being std::move'd though.

clangd/XRefs.cpp
150

Yes, "line" from the protocol is signed, whereas getSpellingColumn/lineNumber returns unsigned. I'll extract another var for the line number and cast both to int instead to have less casts and make the condition smaller.

@malaperle, hi! Both new diff and updating this works, so feel free the one that suits you best. I tend to look over the whole change on each new round of reviews anyway.

clangd/ClangdUnit.cpp
117

We can't have a single map because AST is rebuilt more often than the Preamble, so we have two options:

  • Store a map for the preamble separately, copy it when we need to rebuild the AST and append references from the AST to the new instance of the map.
  • Store two maps: one contains references only from the Preamble, the other one from the AST.

I think both are fine, since the copy of the map will be cheap anyway, as we only store a list of includes inside the main file.

280

That looks fine. Also see the other comment on why we need to copy the map from the Preamble, and not std::move it.

clangd/XRefs.cpp
150

Can we maybe convert to clangd::Position using the helper methods first and do the comparison of two clangd::Positions?
Comparing between clangd::Position and clang's line/column numbers is a common source of off-by-one errors in clangd.

malaperle added inline comments.Jan 10 2018, 9:36 AM
clangd/ClangdUnit.cpp
117

We can't have a single map because AST is rebuilt more often than the Preamble, so we have two options:

Doh! Indeed.

OK so I added the map in PreambleData, this one will say every reparse unless the preamble changes. When the AST is built/rebuilt, the map is copied (or empty) and includes from the AST are appended to it then stored in ParsedAST (option #1?).

clangd/XRefs.cpp
150

offsetToPosition (if that's what you mean) uses a StringRef of the code, which is not handy in this case. I'll add another one "sourceLocToPosition" to convert a SourceLocation to a Position. WDYT? It can be used in a few other places too.

malaperle updated this revision to Diff 129292.Jan 10 2018, 9:38 AM

Store map in PremableData and copy it on reparse.
Convert SourceLoc to Position when comparing with include Positions.

malaperle resigned from this revision.Jan 10 2018, 9:39 AM
malaperle updated this revision to Diff 129293.Jan 10 2018, 9:43 AM

Revert an unintentional white space change.

ilya-biryukov added inline comments.Jan 11 2018, 2:22 AM
clangd/ClangdUnit.h
51

We use unordered_map as a vector<pair<>> here. (i.e. we never look up values by key, because we don't only the range, merely a point in the range)
Replace map with vector<pair<>> and remove RangeHash that we don't need anymore.

clangd/XRefs.cpp
150

Looks good, thanks!

unittests/clangd/ClangdTests.cpp
781

We moved findDefinition tests to XRefsTests.cpp and added a useful Annotation helper to make writing these tests simpler.
Maybe we could use it for this test as well?

malaperle updated this revision to Diff 133978.Feb 12 2018, 7:09 PM

Move tests to XRefsTests, change IncludeReferenceMap to a vector and rename it.

malaperle added inline comments.Feb 12 2018, 7:10 PM
clangd/ClangdUnit.h
51

Done. I also renamed, IncludeReferenceMap to InclusionLocations. I thought I was more suitable.

unittests/clangd/ClangdTests.cpp
781

Done. (I don't know why I can't use the "done" checkbox, maybe because I wasn't the original author?)

ilya-biryukov added inline comments.Feb 13 2018, 6:07 AM
clangd/ClangdUnit.cpp
99

NIT: replace FilenameRange.getAsRange() with SR

121

NIT: remove ctor, use initializer on the member instead:

private:
  SourceManager *SourceMgr = nullptr;
152

Maybe swap IncLocations and SourceMgr? Grouping TopLevelDecls, TopLevelDeclIDs and IncLocations together seems reasonable, as all of them are essentially output parameters.

279

NIT: move IncLocations closer to their first use, i.e. create the variable right before addPPCallbacks()

clangd/ClangdUnit.h
51

LG

97

NIT: move to .cpp file to be consisten with other decls in this file.

clangd/XRefs.cpp
146

NIT: SourceMgr does not depend on the loop variable, declare it out of the loop.

149

NIT: define operator <= for Position and do this instead: R.start <= Pos && Pos < R.end (note that LSP ranges are half-open, i.e. the end is excluded).
Even better: define a bool contains(Position Pos) const helper in the Range class and use it here (will abstract away to half-open nature of the range)

153

Let's follow the pattern of decls and macros here. I.e. not return from the function, merely collect all the results.

unittests/clangd/XRefsTests.cpp
53 ↗(On Diff #133978)

NIT: remove this class, use IgnoreDiagnostics from Compiler.h instead.

245 ↗(On Diff #133978)

Could we also add tests for corner cases: cursor before opening quote, cursor after the closing quote, cursor in the middle of #include token? (we shouldn't navigate anywhere in the middle of the #include token)

malaperle added inline comments.Feb 13 2018, 10:05 AM
unittests/clangd/XRefsTests.cpp
53 ↗(On Diff #133978)

It looks like IgnoreDiagnostics from Compiler.h implements DiagnosticConsumer from Compiler.h, and not DiagnosticsConsumer from ClangdServer.h so that wouldn't work.

malaperle added inline comments.Feb 13 2018, 9:42 PM
unittests/clangd/XRefsTests.cpp
245 ↗(On Diff #133978)

cursor before opening quote, cursor after the closing quote

I assume we don't want to navigate anywhere for these positions? I don't have an opinion.

(we shouldn't navigate anywhere in the middle of the #include token)

It did in CDT and I thought it worked nicely as it made it easier to click on it. You can hold ctrl on the whole line and it underlined it (well except trailing comments). But clients don't handle the spaces nicely (underline between #include and file name) so I thought I'd work on the client first before making the server do it. Anyhow, for now it shouldn't navigate indeed.

ilya-biryukov added inline comments.Feb 14 2018, 5:36 AM
unittests/clangd/XRefsTests.cpp
53 ↗(On Diff #133978)

You're right, I got confused, sorry. Disregard my comment.

245 ↗(On Diff #133978)

> cursor before opening quote, cursor after the closing quote
I assume we don't want to navigate anywhere for these positions? I don't have an opinion.

I'd say we should navigate when the cursor is right before the opening quote. For the closing quote I don't have any opinions either :-)

Fix some NITs, add more tests.

Last drop of NITs. After they're fixed, this change is ready to land!

unittests/clangd/XRefsTests.cpp
282 ↗(On Diff #134296)

There's a typo, should be HeaderAnnotations

302 ↗(On Diff #134296)

NIT: one assertion using EXPECT_THAT will read better and produce more helpful messages in case of failures:

// Create FooHUri to avoid typing URIForFile everywhere.
auto FooHUri = URIForFile{FooH.str()};

EXPECT_THAT(Locations, ElementsAre(Location{FooHUri, HeaderAnnoations.range()}));
328 ↗(On Diff #134296)

NIT: Use EXPECT_THAT here too:
EXPECT_THAT(Locations, IsEmpty());

malaperle updated this revision to Diff 134432.Feb 15 2018, 7:51 AM

Use EXPECT_THAT in a few places and clean-ups in tests.

ilya-biryukov accepted this revision.Feb 15 2018, 8:50 AM

LGTM modulo the ASSERT_TRUE nit.

unittests/clangd/XRefsTests.cpp
295 ↗(On Diff #134432)

Maybe replace with ASSERT_TRUE?
If Locations has an error, an assertion will fire in debug mode inside Expected that the error was not handled.

This revision is now accepted and ready to land.Feb 15 2018, 8:50 AM
malaperle updated this revision to Diff 134549.Feb 15 2018, 7:27 PM

Change some EXPECT_TRUE to ASSERT_TRUE

ilya-biryukov accepted this revision.Feb 16 2018, 2:02 AM
This revision was automatically updated to reflect the committed changes.